rsvs3D  0.0.0
Codes for the c++ implementation of the 3D RSVS
tetgen.cxx
1 // //
3 // TetGen //
4 // //
5 // A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator //
6 // //
7 // Version 1.5 //
8 // August 18, 2018 //
9 // //
10 // Copyright (C) 2002--2018 //
11 // //
12 // TetGen is freely available through the website: http://www.tetgen.org. //
13 // It may be copied, modified, and redistributed for non-commercial use. //
14 // Please consult the file LICENSE for the detailed copyright notices. //
15 // //
17 
18 #include "tetgen.h"
19 
23 
25 // //
26 // load_node_call() Read a list of points from a file. //
27 // //
28 // 'infile' is the file handle contains the node list. It may point to a //
29 // .node, or .poly or .smesh file. 'markers' indicates each node contains an //
30 // additional marker (integer) or not. 'uvflag' indicates each node contains //
31 // u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
32 // of the file being read, it is only used in error messages. //
33 // //
34 // The 'firstnumber' (0 or 1) is automatically determined by the number of //
35 // the first index of the first point. //
36 // //
38 
39 bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
40  char* infilename)
41 {
42  char inputline[INPUTLINESIZE];
43  char *stringptr;
44  REAL x, y, z, attrib;
45  int firstnode, currentmarker;
46  int index, attribindex;
47  int i, j;
48 
49  // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
50  pointlist = new REAL[numberofpoints * 3];
51  if (pointlist == (REAL *) NULL) {
52  terminatetetgen(NULL, 1);
53  }
54  if (numberofpointattributes > 0) {
55  pointattributelist = new REAL[numberofpoints * numberofpointattributes];
56  if (pointattributelist == (REAL *) NULL) {
57  terminatetetgen(NULL, 1);
58  }
59  }
60  if (markers) {
61  pointmarkerlist = new int[numberofpoints];
62  if (pointmarkerlist == (int *) NULL) {
63  terminatetetgen(NULL, 1);
64  }
65  }
66  if (uvflag) {
67  pointparamlist = new pointparam[numberofpoints];
68  if (pointparamlist == NULL) {
69  terminatetetgen(NULL, 1);
70  }
71  }
72 
73  // Read the point section.
74  index = 0;
75  attribindex = 0;
76  for (i = 0; i < numberofpoints; i++) {
77  stringptr = readnumberline(inputline, infile, infilename);
78  if (useindex) {
79  if (i == 0) {
80  firstnode = (int) strtol (stringptr, &stringptr, 0);
81  if ((firstnode == 0) || (firstnode == 1)) {
82  firstnumber = firstnode;
83  }
84  }
85  stringptr = findnextnumber(stringptr);
86  } // if (useindex)
87  if (*stringptr == '\0') {
88  printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
89  break;
90  }
91  x = (REAL) strtod(stringptr, &stringptr);
92  stringptr = findnextnumber(stringptr);
93  if (*stringptr == '\0') {
94  printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
95  break;
96  }
97  y = (REAL) strtod(stringptr, &stringptr);
98  if (mesh_dim == 3) {
99  stringptr = findnextnumber(stringptr);
100  if (*stringptr == '\0') {
101  printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
102  break;
103  }
104  z = (REAL) strtod(stringptr, &stringptr);
105  } else {
106  z = 0.0; // mesh_dim == 2;
107  }
108  pointlist[index++] = x;
109  pointlist[index++] = y;
110  pointlist[index++] = z;
111  // Read the point attributes.
112  for (j = 0; j < numberofpointattributes; j++) {
113  stringptr = findnextnumber(stringptr);
114  if (*stringptr == '\0') {
115  attrib = 0.0;
116  } else {
117  attrib = (REAL) strtod(stringptr, &stringptr);
118  }
119  pointattributelist[attribindex++] = attrib;
120  }
121  if (markers) {
122  // Read a point marker.
123  stringptr = findnextnumber(stringptr);
124  if (*stringptr == '\0') {
125  currentmarker = 0;
126  } else {
127  currentmarker = (int) strtol (stringptr, &stringptr, 0);
128  }
129  pointmarkerlist[i] = currentmarker;
130  }
131  if (uvflag) {
132  // Read point paramteters.
133  stringptr = findnextnumber(stringptr);
134  if (*stringptr == '\0') {
135  printf("Error: Point %d has no uv[0].\n", firstnumber + i);
136  break;
137  }
138  pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
139  stringptr = findnextnumber(stringptr);
140  if (*stringptr == '\0') {
141  printf("Error: Point %d has no uv[1].\n", firstnumber + i);
142  break;
143  }
144  pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
145  stringptr = findnextnumber(stringptr);
146  if (*stringptr == '\0') {
147  printf("Error: Point %d has no tag.\n", firstnumber + i);
148  break;
149  }
150  pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
151  stringptr = findnextnumber(stringptr);
152  if (*stringptr == '\0') {
153  printf("Error: Point %d has no type.\n", firstnumber + i);
154  break;
155  }
156  pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
157  if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
158  printf("Error: Point %d has an invalid type.\n", firstnumber + i);
159  break;
160  }
161  }
162  }
163  if (i < numberofpoints) {
164  // Failed to read points due to some error.
165  delete [] pointlist;
166  pointlist = (REAL *) NULL;
167  if (markers) {
168  delete [] pointmarkerlist;
169  pointmarkerlist = (int *) NULL;
170  }
171  if (numberofpointattributes > 0) {
172  delete [] pointattributelist;
173  pointattributelist = (REAL *) NULL;
174  }
175  if (uvflag) {
176  delete [] pointparamlist;
177  pointparamlist = NULL;
178  }
179  numberofpoints = 0;
180  return false;
181  }
182  return true;
183 }
184 
186 // //
187 // load_node() Load a list of points from a .node file. //
188 // //
190 
191 bool tetgenio::load_node(char* filebasename)
192 {
193  FILE *infile;
194  char innodefilename[FILENAMESIZE];
195  char inputline[INPUTLINESIZE];
196  char *stringptr;
197  bool okflag;
198  int markers;
199  int uvflag; // for psc input.
200 
201  // Assembling the actual file names we want to open.
202  strcpy(innodefilename, filebasename);
203  strcat(innodefilename, ".node");
204 
205  // Try to open a .node file.
206  infile = fopen(innodefilename, "r");
207  if (infile == (FILE *) NULL) {
208  printf(" Cannot access file %s.\n", innodefilename);
209  return false;
210  }
211  printf("Opening %s.\n", innodefilename);
212 
213  // Set initial flags.
214  mesh_dim = 3;
215  numberofpointattributes = 0; // no point attribute.
216  markers = 0; // no boundary marker.
217  uvflag = 0; // no uv parameters (required by a PSC).
218 
219  // Read the first line of the file.
220  stringptr = readnumberline(inputline, infile, innodefilename);
221  // Does this file contain an index column?
222  stringptr = strstr(inputline, "rbox");
223  if (stringptr == NULL) {
224  // Read number of points, number of dimensions, number of point
225  // attributes, and number of boundary markers.
226  stringptr = inputline;
227  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
228  stringptr = findnextnumber(stringptr);
229  if (*stringptr != '\0') {
230  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
231  }
232  stringptr = findnextnumber(stringptr);
233  if (*stringptr != '\0') {
234  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
235  }
236  stringptr = findnextnumber(stringptr);
237  if (*stringptr != '\0') {
238  markers = (int) strtol (stringptr, &stringptr, 0);
239  }
240  stringptr = findnextnumber(stringptr);
241  if (*stringptr != '\0') {
242  uvflag = (int) strtol (stringptr, &stringptr, 0);
243  }
244  } else {
245  // It is a rbox (qhull) input file.
246  stringptr = inputline;
247  // Get the dimension.
248  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
249  // Get the number of points.
250  stringptr = readnumberline(inputline, infile, innodefilename);
251  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
252  // There is no index column.
253  useindex = 0;
254  }
255 
256  // Load the list of nodes.
257  okflag = load_node_call(infile, markers, uvflag, innodefilename);
258 
259  fclose(infile);
260  return okflag;
261 }
262 
264 // //
265 // load_edge() Load a list of edges from a .edge file. //
266 // //
268 
269 bool tetgenio::load_edge(char* filebasename)
270 {
271  FILE *infile;
272  char inedgefilename[FILENAMESIZE];
273  char inputline[INPUTLINESIZE];
274  char *stringptr;
275  int markers, corner;
276  int index;
277  int i, j;
278 
279  strcpy(inedgefilename, filebasename);
280  strcat(inedgefilename, ".edge");
281 
282  infile = fopen(inedgefilename, "r");
283  if (infile != (FILE *) NULL) {
284  printf("Opening %s.\n", inedgefilename);
285  } else {
286  //printf(" Cannot access file %s.\n", inedgefilename);
287  return false;
288  }
289 
290  // Read number of boundary edges.
291  stringptr = readnumberline(inputline, infile, inedgefilename);
292  numberofedges = (int) strtol (stringptr, &stringptr, 0);
293  if (numberofedges > 0) {
294  edgelist = new int[numberofedges * 2];
295  if (edgelist == (int *) NULL) {
296  terminatetetgen(NULL, 1);
297  }
298  stringptr = findnextnumber(stringptr);
299  if (*stringptr == '\0') {
300  markers = 0; // Default value.
301  } else {
302  markers = (int) strtol (stringptr, &stringptr, 0);
303  }
304  if (markers > 0) {
305  edgemarkerlist = new int[numberofedges];
306  }
307  }
308 
309  // Read the list of edges.
310  index = 0;
311  for (i = 0; i < numberofedges; i++) {
312  // Read edge index and the edge's two endpoints.
313  stringptr = readnumberline(inputline, infile, inedgefilename);
314  for (j = 0; j < 2; j++) {
315  stringptr = findnextnumber(stringptr);
316  if (*stringptr == '\0') {
317  printf("Error: Edge %d is missing vertex %d in %s.\n",
318  i + firstnumber, j + 1, inedgefilename);
319  terminatetetgen(NULL, 1);
320  }
321  corner = (int) strtol(stringptr, &stringptr, 0);
322  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
323  printf("Error: Edge %d has an invalid vertex index.\n",
324  i + firstnumber);
325  terminatetetgen(NULL, 1);
326  }
327  edgelist[index++] = corner;
328  }
329  if (numberofcorners == 10) {
330  // Skip an extra vertex (generated by a previous -o2 option).
331  stringptr = findnextnumber(stringptr);
332  }
333  // Read the edge marker if it has.
334  if (markers) {
335  stringptr = findnextnumber(stringptr);
336  edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
337  }
338  }
339 
340  fclose(infile);
341  return true;
342 }
343 
345 // //
346 // load_face() Load a list of faces (triangles) from a .face file. //
347 // //
349 
350 bool tetgenio::load_face(char* filebasename)
351 {
352  FILE *infile;
353  char infilename[FILENAMESIZE];
354  char inputline[INPUTLINESIZE];
355  char *stringptr;
356  REAL attrib;
357  int markers, corner;
358  int index;
359  int i, j;
360 
361  strcpy(infilename, filebasename);
362  strcat(infilename, ".face");
363 
364  infile = fopen(infilename, "r");
365  if (infile != (FILE *) NULL) {
366  printf("Opening %s.\n", infilename);
367  } else {
368  return false;
369  }
370 
371  // Read number of faces, boundary markers.
372  stringptr = readnumberline(inputline, infile, infilename);
373  numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
374  stringptr = findnextnumber(stringptr);
375  if (mesh_dim == 2) {
376  // Skip a number.
377  stringptr = findnextnumber(stringptr);
378  }
379  if (*stringptr == '\0') {
380  markers = 0; // Default there is no marker per face.
381  } else {
382  markers = (int) strtol (stringptr, &stringptr, 0);
383  }
384  if (numberoftrifaces > 0) {
385  trifacelist = new int[numberoftrifaces * 3];
386  if (trifacelist == (int *) NULL) {
387  terminatetetgen(NULL, 1);
388  }
389  if (markers) {
390  trifacemarkerlist = new int[numberoftrifaces];
391  if (trifacemarkerlist == (int *) NULL) {
392  terminatetetgen(NULL, 1);
393  }
394  }
395  }
396 
397  // Read the list of faces.
398  index = 0;
399  for (i = 0; i < numberoftrifaces; i++) {
400  // Read face index and the face's three corners.
401  stringptr = readnumberline(inputline, infile, infilename);
402  for (j = 0; j < 3; j++) {
403  stringptr = findnextnumber(stringptr);
404  if (*stringptr == '\0') {
405  printf("Error: Face %d is missing vertex %d in %s.\n",
406  i + firstnumber, j + 1, infilename);
407  terminatetetgen(NULL, 1);
408  }
409  corner = (int) strtol(stringptr, &stringptr, 0);
410  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
411  printf("Error: Face %d has an invalid vertex index.\n",
412  i + firstnumber);
413  terminatetetgen(NULL, 1);
414  }
415  trifacelist[index++] = corner;
416  }
417  if (numberofcorners == 10) {
418  // Skip 3 extra vertices (generated by a previous -o2 option).
419  for (j = 0; j < 3; j++) {
420  stringptr = findnextnumber(stringptr);
421  }
422  }
423  // Read the boundary marker if it exists.
424  if (markers) {
425  stringptr = findnextnumber(stringptr);
426  if (*stringptr == '\0') {
427  attrib = 0.0;
428  } else {
429  attrib = (REAL) strtod(stringptr, &stringptr);
430  }
431  trifacemarkerlist[i] = (int) attrib;
432  }
433  }
434 
435  fclose(infile);
436 
437  return true;
438 }
439 
441 // //
442 // load_tet() Load a list of tetrahedra from a .ele file. //
443 // //
445 
446 bool tetgenio::load_tet(char* filebasename)
447 {
448  FILE *infile;
449  char infilename[FILENAMESIZE];
450  char inputline[INPUTLINESIZE];
451  char *stringptr;
452  REAL attrib;
453  int corner;
454  int index, attribindex;
455  int i, j;
456 
457  strcpy(infilename, filebasename);
458  strcat(infilename, ".ele");
459 
460  infile = fopen(infilename, "r");
461  if (infile != (FILE *) NULL) {
462  printf("Opening %s.\n", infilename);
463  } else {
464  return false;
465  }
466 
467  // Read number of elements, number of corners (4 or 10), number of
468  // element attributes.
469  stringptr = readnumberline(inputline, infile, infilename);
470  numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
471  if (numberoftetrahedra <= 0) {
472  printf("Error: Invalid number of tetrahedra.\n");
473  fclose(infile);
474  return false;
475  }
476  stringptr = findnextnumber(stringptr);
477  if (*stringptr == '\0') {
478  numberofcorners = 4; // Default read 4 nodes per element.
479  } else {
480  numberofcorners = (int) strtol(stringptr, &stringptr, 0);
481  }
482  stringptr = findnextnumber(stringptr);
483  if (*stringptr == '\0') {
484  numberoftetrahedronattributes = 0; // Default no attribute.
485  } else {
486  numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
487  }
488  if (numberofcorners != 4 && numberofcorners != 10) {
489  printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
490  numberofcorners);
491  fclose(infile);
492  return false;
493  }
494 
495  // Allocate memory for tetrahedra.
496  tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
497  if (tetrahedronlist == (int *) NULL) {
498  terminatetetgen(NULL, 1);
499  }
500  // Allocate memory for output tetrahedron attributes if necessary.
501  if (numberoftetrahedronattributes > 0) {
502  tetrahedronattributelist = new REAL[numberoftetrahedra *
503  numberoftetrahedronattributes];
504  if (tetrahedronattributelist == (REAL *) NULL) {
505  terminatetetgen(NULL, 1);
506  }
507  }
508 
509  // Read the list of tetrahedra.
510  index = 0;
511  attribindex = 0;
512  for (i = 0; i < numberoftetrahedra; i++) {
513  // Read tetrahedron index and the tetrahedron's corners.
514  stringptr = readnumberline(inputline, infile, infilename);
515  for (j = 0; j < numberofcorners; j++) {
516  stringptr = findnextnumber(stringptr);
517  if (*stringptr == '\0') {
518  printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
519  i + firstnumber, j + 1, infilename);
520  terminatetetgen(NULL, 1);
521  }
522  corner = (int) strtol(stringptr, &stringptr, 0);
523  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
524  printf("Error: Tetrahedron %d has an invalid vertex index.\n",
525  i + firstnumber);
526  terminatetetgen(NULL, 1);
527  }
528  tetrahedronlist[index++] = corner;
529  }
530  // Read the tetrahedron's attributes.
531  for (j = 0; j < numberoftetrahedronattributes; j++) {
532  stringptr = findnextnumber(stringptr);
533  if (*stringptr == '\0') {
534  attrib = 0.0;
535  } else {
536  attrib = (REAL) strtod(stringptr, &stringptr);
537  }
538  tetrahedronattributelist[attribindex++] = attrib;
539  }
540  }
541 
542  fclose(infile);
543 
544  return true;
545 }
546 
548 // //
549 // load_vol() Load a list of volume constraints from a .vol file. //
550 // //
552 
553 bool tetgenio::load_vol(char* filebasename)
554 {
555  FILE *infile;
556  char inelefilename[FILENAMESIZE];
557  char infilename[FILENAMESIZE];
558  char inputline[INPUTLINESIZE];
559  char *stringptr;
560  REAL volume;
561  int volelements;
562  int i;
563 
564  strcpy(infilename, filebasename);
565  strcat(infilename, ".vol");
566 
567  infile = fopen(infilename, "r");
568  if (infile != (FILE *) NULL) {
569  printf("Opening %s.\n", infilename);
570  } else {
571  return false;
572  }
573 
574  // Read number of tetrahedra.
575  stringptr = readnumberline(inputline, infile, infilename);
576  volelements = (int) strtol (stringptr, &stringptr, 0);
577  if (volelements != numberoftetrahedra) {
578  strcpy(inelefilename, filebasename);
579  strcat(infilename, ".ele");
580  printf("Warning: %s and %s disagree on number of tetrahedra.\n",
581  inelefilename, infilename);
582  fclose(infile);
583  return false;
584  }
585 
586  tetrahedronvolumelist = new REAL[volelements];
587  if (tetrahedronvolumelist == (REAL *) NULL) {
588  terminatetetgen(NULL, 1);
589  }
590 
591  // Read the list of volume constraints.
592  for (i = 0; i < volelements; i++) {
593  stringptr = readnumberline(inputline, infile, infilename);
594  stringptr = findnextnumber(stringptr);
595  if (*stringptr == '\0') {
596  volume = -1.0; // No constraint on this tetrahedron.
597  } else {
598  volume = (REAL) strtod(stringptr, &stringptr);
599  }
600  tetrahedronvolumelist[i] = volume;
601  }
602 
603  fclose(infile);
604 
605  return true;
606 }
607 
609 // //
610 // load_var() Load constraints applied on facets, segments, and nodes //
611 // from a .var file. //
612 // //
614 
615 bool tetgenio::load_var(char* filebasename)
616 {
617  FILE *infile;
618  char varfilename[FILENAMESIZE];
619  char inputline[INPUTLINESIZE];
620  char *stringptr;
621  int index;
622  int i;
623 
624  // Variant constraints are saved in file "filename.var".
625  strcpy(varfilename, filebasename);
626  strcat(varfilename, ".var");
627  infile = fopen(varfilename, "r");
628  if (infile != (FILE *) NULL) {
629  printf("Opening %s.\n", varfilename);
630  } else {
631  return false;
632  }
633 
634  // Read the facet constraint section.
635  stringptr = readnumberline(inputline, infile, varfilename);
636  if (stringptr == NULL) {
637  // No region list, return.
638  fclose(infile);
639  return true;
640  }
641  if (*stringptr != '\0') {
642  numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
643  } else {
644  numberoffacetconstraints = 0;
645  }
646  if (numberoffacetconstraints > 0) {
647  // Initialize 'facetconstraintlist'.
648  facetconstraintlist = new REAL[numberoffacetconstraints * 2];
649  index = 0;
650  for (i = 0; i < numberoffacetconstraints; i++) {
651  stringptr = readnumberline(inputline, infile, varfilename);
652  stringptr = findnextnumber(stringptr);
653  if (*stringptr == '\0') {
654  printf("Error: facet constraint %d has no facet marker.\n",
655  firstnumber + i);
656  break;
657  } else {
658  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
659  }
660  stringptr = findnextnumber(stringptr);
661  if (*stringptr == '\0') {
662  printf("Error: facet constraint %d has no maximum area bound.\n",
663  firstnumber + i);
664  break;
665  } else {
666  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
667  }
668  }
669  if (i < numberoffacetconstraints) {
670  // This must be caused by an error.
671  fclose(infile);
672  return false;
673  }
674  }
675 
676  // Read the segment constraint section.
677  stringptr = readnumberline(inputline, infile, varfilename);
678  if (stringptr == NULL) {
679  // No segment list, return.
680  fclose(infile);
681  return true;
682  }
683  if (*stringptr != '\0') {
684  numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
685  } else {
686  numberofsegmentconstraints = 0;
687  }
688  if (numberofsegmentconstraints > 0) {
689  // Initialize 'segmentconstraintlist'.
690  segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
691  index = 0;
692  for (i = 0; i < numberofsegmentconstraints; i++) {
693  stringptr = readnumberline(inputline, infile, varfilename);
694  stringptr = findnextnumber(stringptr);
695  if (*stringptr == '\0') {
696  printf("Error: segment constraint %d has no frist endpoint.\n",
697  firstnumber + i);
698  break;
699  } else {
700  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
701  }
702  stringptr = findnextnumber(stringptr);
703  if (*stringptr == '\0') {
704  printf("Error: segment constraint %d has no second endpoint.\n",
705  firstnumber + i);
706  break;
707  } else {
708  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
709  }
710  stringptr = findnextnumber(stringptr);
711  if (*stringptr == '\0') {
712  printf("Error: segment constraint %d has no maximum length bound.\n",
713  firstnumber + i);
714  break;
715  } else {
716  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
717  }
718  }
719  if (i < numberofsegmentconstraints) {
720  // This must be caused by an error.
721  fclose(infile);
722  return false;
723  }
724  }
725 
726  fclose(infile);
727  return true;
728 }
729 
731 // //
732 // load_mtr() Load a size specification map from a .mtr file. //
733 // //
735 
736 bool tetgenio::load_mtr(char* filebasename)
737 {
738  FILE *infile;
739  char mtrfilename[FILENAMESIZE];
740  char inputline[INPUTLINESIZE];
741  char *stringptr;
742  REAL mtr;
743  int ptnum;
744  int mtrindex;
745  int i, j;
746 
747  strcpy(mtrfilename, filebasename);
748  strcat(mtrfilename, ".mtr");
749  infile = fopen(mtrfilename, "r");
750  if (infile != (FILE *) NULL) {
751  printf("Opening %s.\n", mtrfilename);
752  } else {
753  return false;
754  }
755 
756  // Read the number of points.
757  stringptr = readnumberline(inputline, infile, mtrfilename);
758  ptnum = (int) strtol (stringptr, &stringptr, 0);
759  if (ptnum != numberofpoints) {
760  printf(" !! Point numbers are not equal. Ignored.\n");
761  fclose(infile);
762  return false;
763  }
764  // Read the number of columns (1, 3, or 6).
765  stringptr = findnextnumber(stringptr); // Skip number of points.
766  if (*stringptr != '\0') {
767  numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
768  }
769  if ((numberofpointmtrs != 1) && (numberofpointmtrs != 3) &&
770  (numberofpointmtrs != 6)) {
771  // Column number doesn't match.
772  numberofpointmtrs = 0;
773  printf(" !! Metric size does not match (1, 3, or 6). Ignored.\n");
774  fclose(infile);
775  return false;
776  }
777 
778  // Allocate space for pointmtrlist.
779  pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
780  if (pointmtrlist == (REAL *) NULL) {
781  terminatetetgen(NULL, 1);
782  }
783  mtrindex = 0;
784  for (i = 0; i < numberofpoints; i++) {
785  // Read metrics.
786  stringptr = readnumberline(inputline, infile, mtrfilename);
787  for (j = 0; j < numberofpointmtrs; j++) {
788  if (*stringptr == '\0') {
789  printf("Error: Metric %d is missing value #%d in %s.\n",
790  i + firstnumber, j + 1, mtrfilename);
791  terminatetetgen(NULL, 1);
792  }
793  mtr = (REAL) strtod(stringptr, &stringptr);
794  pointmtrlist[mtrindex++] = mtr;
795  stringptr = findnextnumber(stringptr);
796  }
797  }
798 
799  fclose(infile);
800  return true;
801 }
802 
804 // //
805 // load_poly() Load a PL complex from a .poly or a .smesh file. //
806 // //
808 
809 bool tetgenio::load_poly(char* filebasename)
810 {
811  FILE *infile;
812  char inpolyfilename[FILENAMESIZE];
813  char insmeshfilename[FILENAMESIZE];
814  char inputline[INPUTLINESIZE];
815  char *stringptr, *infilename;
816  int smesh, markers, uvflag, currentmarker;
817  int index;
818  int i, j, k;
819 
820  // Assembling the actual file names we want to open.
821  strcpy(inpolyfilename, filebasename);
822  strcpy(insmeshfilename, filebasename);
823  strcat(inpolyfilename, ".poly");
824  strcat(insmeshfilename, ".smesh");
825 
826  // First assume it is a .poly file.
827  smesh = 0;
828  // Try to open a .poly file.
829  infile = fopen(inpolyfilename, "r");
830  if (infile == (FILE *) NULL) {
831  // .poly doesn't exist! Try to open a .smesh file.
832  infile = fopen(insmeshfilename, "r");
833  if (infile == (FILE *) NULL) {
834  printf(" Cannot access file %s and %s.\n",
835  inpolyfilename, insmeshfilename);
836  return false;
837  } else {
838  printf("Opening %s.\n", insmeshfilename);
839  infilename = insmeshfilename;
840  }
841  smesh = 1;
842  } else {
843  printf("Opening %s.\n", inpolyfilename);
844  infilename = inpolyfilename;
845  }
846 
847  // Initialize the default values.
848  mesh_dim = 3; // Three-dimensional coordinates.
849  numberofpointattributes = 0; // no point attribute.
850  markers = 0; // no boundary marker.
851  uvflag = 0; // no uv parameters (required by a PSC).
852 
853  // Read number of points, number of dimensions, number of point
854  // attributes, and number of boundary markers.
855  stringptr = readnumberline(inputline, infile, infilename);
856  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
857  stringptr = findnextnumber(stringptr);
858  if (*stringptr != '\0') {
859  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
860  }
861  stringptr = findnextnumber(stringptr);
862  if (*stringptr != '\0') {
863  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
864  }
865  stringptr = findnextnumber(stringptr);
866  if (*stringptr != '\0') {
867  markers = (int) strtol (stringptr, &stringptr, 0);
868  }
869  if (*stringptr != '\0') {
870  uvflag = (int) strtol (stringptr, &stringptr, 0);
871  }
872 
873  if (numberofpoints > 0) {
874  // Load the list of nodes.
875  if (!load_node_call(infile, markers, uvflag, infilename)) {
876  fclose(infile);
877  return false;
878  }
879  } else {
880  // If the .poly or .smesh file claims there are zero points, that
881  // means the points should be read from a separate .node file.
882  if (!load_node(filebasename)) {
883  fclose(infile);
884  return false;
885  }
886  }
887 
888  if ((mesh_dim != 3) && (mesh_dim != 2)) {
889  printf("Input error: TetGen only works for 2D & 3D point sets.\n");
890  fclose(infile);
891  return false;
892  }
893  if (numberofpoints < (mesh_dim + 1)) {
894  printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
895  fclose(infile);
896  return false;
897  }
898 
899  facet *f;
900  polygon *p;
901 
902  if (mesh_dim == 3) {
903 
904  // Read number of facets and number of boundary markers.
905  stringptr = readnumberline(inputline, infile, infilename);
906  if (stringptr == NULL) {
907  // No facet list, return.
908  fclose(infile);
909  return true;
910  }
911  numberoffacets = (int) strtol (stringptr, &stringptr, 0);
912  if (numberoffacets <= 0) {
913  // No facet list, return.
914  fclose(infile);
915  return true;
916  }
917  stringptr = findnextnumber(stringptr);
918  if (*stringptr == '\0') {
919  markers = 0; // no boundary marker.
920  } else {
921  markers = (int) strtol (stringptr, &stringptr, 0);
922  }
923 
924  // Initialize the 'facetlist', 'facetmarkerlist'.
925  facetlist = new facet[numberoffacets];
926  if (markers == 1) {
927  facetmarkerlist = new int[numberoffacets];
928  }
929 
930  // Read data into 'facetlist', 'facetmarkerlist'.
931  if (smesh == 0) {
932  // Facets are in .poly file format.
933  for (i = 1; i <= numberoffacets; i++) {
934  f = &(facetlist[i - 1]);
935  init(f);
936  f->numberofholes = 0;
937  currentmarker = 0;
938  // Read number of polygons, number of holes, and a boundary marker.
939  stringptr = readnumberline(inputline, infile, infilename);
940  f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
941  stringptr = findnextnumber(stringptr);
942  if (*stringptr != '\0') {
943  f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
944  if (markers == 1) {
945  stringptr = findnextnumber(stringptr);
946  if (*stringptr != '\0') {
947  currentmarker = (int) strtol(stringptr, &stringptr, 0);
948  }
949  }
950  }
951  // Initialize facetmarker if it needs.
952  if (markers == 1) {
953  facetmarkerlist[i - 1] = currentmarker;
954  }
955  // Each facet should has at least one polygon.
956  if (f->numberofpolygons <= 0) {
957  printf("Error: Wrong number of polygon in %d facet.\n", i);
958  break;
959  }
960  // Initialize the 'f->polygonlist'.
961  f->polygonlist = new polygon[f->numberofpolygons];
962  // Go through all polygons, read in their vertices.
963  for (j = 1; j <= f->numberofpolygons; j++) {
964  p = &(f->polygonlist[j - 1]);
965  init(p);
966  // Read number of vertices of this polygon.
967  stringptr = readnumberline(inputline, infile, infilename);
968  p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
969  if (p->numberofvertices < 1) {
970  printf("Error: Wrong polygon %d in facet %d\n", j, i);
971  break;
972  }
973  // Initialize 'p->vertexlist'.
974  p->vertexlist = new int[p->numberofvertices];
975  // Read all vertices of this polygon.
976  for (k = 1; k <= p->numberofvertices; k++) {
977  stringptr = findnextnumber(stringptr);
978  if (*stringptr == '\0') {
979  // Try to load another non-empty line and continue to read the
980  // rest of vertices.
981  stringptr = readnumberline(inputline, infile, infilename);
982  if (*stringptr == '\0') {
983  printf("Error: Missing %d endpoints of polygon %d in facet %d",
984  p->numberofvertices - k, j, i);
985  break;
986  }
987  }
988  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
989  }
990  }
991  if (j <= f->numberofpolygons) {
992  // This must be caused by an error. However, there're j - 1
993  // polygons have been read. Reset the 'f->numberofpolygon'.
994  if (j == 1) {
995  // This is the first polygon.
996  delete [] f->polygonlist;
997  }
998  f->numberofpolygons = j - 1;
999  // No hole will be read even it exists.
1000  f->numberofholes = 0;
1001  break;
1002  }
1003  // If this facet has hole pints defined, read them.
1004  if (f->numberofholes > 0) {
1005  // Initialize 'f->holelist'.
1006  f->holelist = new REAL[f->numberofholes * 3];
1007  // Read the holes' coordinates.
1008  index = 0;
1009  for (j = 1; j <= f->numberofholes; j++) {
1010  stringptr = readnumberline(inputline, infile, infilename);
1011  for (k = 1; k <= 3; k++) {
1012  stringptr = findnextnumber(stringptr);
1013  if (*stringptr == '\0') {
1014  printf("Error: Hole %d in facet %d has no coordinates", j, i);
1015  break;
1016  }
1017  f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1018  }
1019  if (k <= 3) {
1020  // This must be caused by an error.
1021  break;
1022  }
1023  }
1024  if (j <= f->numberofholes) {
1025  // This must be caused by an error.
1026  break;
1027  }
1028  }
1029  }
1030  if (i <= numberoffacets) {
1031  // This must be caused by an error.
1032  numberoffacets = i - 1;
1033  fclose(infile);
1034  return false;
1035  }
1036  } else { // poly == 0
1037  // Read the facets from a .smesh file.
1038  for (i = 1; i <= numberoffacets; i++) {
1039  f = &(facetlist[i - 1]);
1040  init(f);
1041  // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1042  // contains exactly one polygon, no hole.
1043  f->numberofpolygons = 1;
1044  f->polygonlist = new polygon[f->numberofpolygons];
1045  p = &(f->polygonlist[0]);
1046  init(p);
1047  // Read number of vertices of this polygon.
1048  stringptr = readnumberline(inputline, infile, insmeshfilename);
1049  p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1050  if (p->numberofvertices < 1) {
1051  printf("Error: Wrong number of vertex in facet %d\n", i);
1052  break;
1053  }
1054  // Initialize 'p->vertexlist'.
1055  p->vertexlist = new int[p->numberofvertices];
1056  for (k = 1; k <= p->numberofvertices; k++) {
1057  stringptr = findnextnumber(stringptr);
1058  if (*stringptr == '\0') {
1059  // Try to load another non-empty line and continue to read the
1060  // rest of vertices.
1061  stringptr = readnumberline(inputline, infile, infilename);
1062  if (*stringptr == '\0') {
1063  printf("Error: Missing %d endpoints in facet %d",
1064  p->numberofvertices - k, i);
1065  break;
1066  }
1067  }
1068  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1069  }
1070  if (k <= p->numberofvertices) {
1071  // This must be caused by an error.
1072  break;
1073  }
1074  // Read facet's boundary marker at last.
1075  if (markers == 1) {
1076  stringptr = findnextnumber(stringptr);
1077  if (*stringptr == '\0') {
1078  currentmarker = 0;
1079  } else {
1080  currentmarker = (int) strtol(stringptr, &stringptr, 0);
1081  }
1082  facetmarkerlist[i - 1] = currentmarker;
1083  }
1084  }
1085  if (i <= numberoffacets) {
1086  // This must be caused by an error.
1087  numberoffacets = i - 1;
1088  fclose(infile);
1089  return false;
1090  }
1091  }
1092 
1093  // Read the hole section.
1094  stringptr = readnumberline(inputline, infile, infilename);
1095  if (stringptr == NULL) {
1096  // No hole list, return.
1097  fclose(infile);
1098  return true;
1099  }
1100  if (*stringptr != '\0') {
1101  numberofholes = (int) strtol (stringptr, &stringptr, 0);
1102  } else {
1103  numberofholes = 0;
1104  }
1105  if (numberofholes > 0) {
1106  // Initialize 'holelist'.
1107  holelist = new REAL[numberofholes * 3];
1108  for (i = 0; i < 3 * numberofholes; i += 3) {
1109  stringptr = readnumberline(inputline, infile, infilename);
1110  stringptr = findnextnumber(stringptr);
1111  if (*stringptr == '\0') {
1112  printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
1113  break;
1114  } else {
1115  holelist[i] = (REAL) strtod(stringptr, &stringptr);
1116  }
1117  stringptr = findnextnumber(stringptr);
1118  if (*stringptr == '\0') {
1119  printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
1120  break;
1121  } else {
1122  holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1123  }
1124  stringptr = findnextnumber(stringptr);
1125  if (*stringptr == '\0') {
1126  printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
1127  break;
1128  } else {
1129  holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1130  }
1131  }
1132  if (i < 3 * numberofholes) {
1133  // This must be caused by an error.
1134  fclose(infile);
1135  return false;
1136  }
1137  }
1138 
1139  // Read the region section. The 'region' section is optional, if we
1140  // don't reach the end-of-file, try read it in.
1141  stringptr = readnumberline(inputline, infile, NULL);
1142  if (stringptr != (char *) NULL && *stringptr != '\0') {
1143  numberofregions = (int) strtol (stringptr, &stringptr, 0);
1144  } else {
1145  numberofregions = 0;
1146  }
1147  if (numberofregions > 0) {
1148  // Initialize 'regionlist'.
1149  regionlist = new REAL[numberofregions * 5];
1150  index = 0;
1151  for (i = 0; i < numberofregions; i++) {
1152  stringptr = readnumberline(inputline, infile, infilename);
1153  stringptr = findnextnumber(stringptr);
1154  if (*stringptr == '\0') {
1155  printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
1156  break;
1157  } else {
1158  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1159  }
1160  stringptr = findnextnumber(stringptr);
1161  if (*stringptr == '\0') {
1162  printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
1163  break;
1164  } else {
1165  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1166  }
1167  stringptr = findnextnumber(stringptr);
1168  if (*stringptr == '\0') {
1169  printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
1170  break;
1171  } else {
1172  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1173  }
1174  stringptr = findnextnumber(stringptr);
1175  if (*stringptr == '\0') {
1176  printf("Error: Region %d has no region attrib.\n", firstnumber + i);
1177  break;
1178  } else {
1179  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1180  }
1181  stringptr = findnextnumber(stringptr);
1182  if (*stringptr == '\0') {
1183  regionlist[index] = regionlist[index - 1];
1184  } else {
1185  regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1186  }
1187  index++;
1188  }
1189  if (i < numberofregions) {
1190  // This must be caused by an error.
1191  fclose(infile);
1192  return false;
1193  }
1194  }
1195 
1196  }
1197 
1198  // End of reading poly/smesh file.
1199  fclose(infile);
1200  return true;
1201 }
1202 
1204 // //
1205 // load_off() Load a polyhedron from a .off file. //
1206 // //
1207 // The .off format is one of file formats of the Geomview, an interactive //
1208 // program for viewing and manipulating geometric objects. More information //
1209 // is available form: http://www.geomview.org. //
1210 // //
1212 
1213 bool tetgenio::load_off(char* filebasename)
1214 {
1215  FILE *fp;
1216  tetgenio::facet *f;
1217  tetgenio::polygon *p;
1218  char infilename[FILENAMESIZE];
1219  char buffer[INPUTLINESIZE];
1220  char *bufferp;
1221  double *coord;
1222  int nverts = 0, iverts = 0;
1223  int nfaces = 0, ifaces = 0;
1224  int nedges = 0;
1225  int line_count = 0, i;
1226 
1227  // Default, the off file's index is from '0'. We check it by remembering the
1228  // smallest index we found in the file. It should be either 0 or 1.
1229  int smallestidx = 0;
1230 
1231  strncpy(infilename, filebasename, 1024 - 1);
1232  infilename[FILENAMESIZE - 1] = '\0';
1233  if (infilename[0] == '\0') {
1234  printf("Error: No filename.\n");
1235  return false;
1236  }
1237  if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1238  strcat(infilename, ".off");
1239  }
1240 
1241  if (!(fp = fopen(infilename, "r"))) {
1242  printf(" Unable to open file %s\n", infilename);
1243  return false;
1244  }
1245  printf("Opening %s.\n", infilename);
1246 
1247  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1248  // Check section
1249  if (nverts == 0) {
1250  // Read header
1251  bufferp = strstr(bufferp, "OFF");
1252  if (bufferp != NULL) {
1253  // Read mesh counts
1254  bufferp = findnextnumber(bufferp); // Skip field "OFF".
1255  if (*bufferp == '\0') {
1256  // Read a non-empty line.
1257  bufferp = readline(buffer, fp, &line_count);
1258  }
1259  if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1260  || (nverts == 0)) {
1261  printf("Syntax error reading header on line %d in file %s\n",
1262  line_count, infilename);
1263  fclose(fp);
1264  return false;
1265  }
1266  // Allocate memory for 'tetgenio'
1267  if (nverts > 0) {
1268  numberofpoints = nverts;
1269  pointlist = new REAL[nverts * 3];
1270  smallestidx = nverts + 1; // A bigger enough number.
1271  }
1272  if (nfaces > 0) {
1273  numberoffacets = nfaces;
1274  facetlist = new tetgenio::facet[nfaces];
1275  }
1276  }
1277  } else if (iverts < nverts) {
1278  // Read vertex coordinates
1279  coord = &pointlist[iverts * 3];
1280  for (i = 0; i < 3; i++) {
1281  if (*bufferp == '\0') {
1282  printf("Syntax error reading vertex coords on line %d in file %s\n",
1283  line_count, infilename);
1284  fclose(fp);
1285  return false;
1286  }
1287  coord[i] = (REAL) strtod(bufferp, &bufferp);
1288  bufferp = findnextnumber(bufferp);
1289  }
1290  iverts++;
1291  } else if (ifaces < nfaces) {
1292  // Get next face
1293  f = &facetlist[ifaces];
1294  init(f);
1295  // In .off format, each facet has one polygon, no hole.
1296  f->numberofpolygons = 1;
1297  f->polygonlist = new tetgenio::polygon[1];
1298  p = &f->polygonlist[0];
1299  init(p);
1300  // Read the number of vertices, it should be greater than 0.
1301  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1302  if (p->numberofvertices == 0) {
1303  printf("Syntax error reading polygon on line %d in file %s\n",
1304  line_count, infilename);
1305  fclose(fp);
1306  return false;
1307  }
1308  // Allocate memory for face vertices
1309  p->vertexlist = new int[p->numberofvertices];
1310  for (i = 0; i < p->numberofvertices; i++) {
1311  bufferp = findnextnumber(bufferp);
1312  if (*bufferp == '\0') {
1313  printf("Syntax error reading polygon on line %d in file %s\n",
1314  line_count, infilename);
1315  fclose(fp);
1316  return false;
1317  }
1318  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1319  // Detect the smallest index.
1320  if (p->vertexlist[i] < smallestidx) {
1321  smallestidx = p->vertexlist[i];
1322  }
1323  }
1324  ifaces++;
1325  } else {
1326  // Should never get here
1327  printf("Found extra text starting at line %d in file %s\n", line_count,
1328  infilename);
1329  break;
1330  }
1331  }
1332 
1333  // Close file
1334  fclose(fp);
1335 
1336  // Decide the firstnumber of the index.
1337  if (smallestidx == 0) {
1338  firstnumber = 0;
1339  } else if (smallestidx == 1) {
1340  firstnumber = 1;
1341  } else {
1342  printf("A wrong smallest index (%d) was detected in file %s\n",
1343  smallestidx, infilename);
1344  return false;
1345  }
1346 
1347  if (iverts != nverts) {
1348  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1349  nverts, iverts, infilename);
1350  return false;
1351  }
1352  if (ifaces != nfaces) {
1353  printf("Expected %d faces, but read only %d faces in file %s\n",
1354  nfaces, ifaces, infilename);
1355  return false;
1356  }
1357 
1358  return true;
1359 }
1360 
1362 // //
1363 // load_ply() Load a polyhedron from a .ply file. //
1364 // //
1365 // This is a simplified version of reading .ply files, which only reads the //
1366 // set of vertices and the set of faces. Other informations (such as color, //
1367 // material, texture, etc) in .ply file are ignored. Complete routines for //
1368 // reading and writing ,ply files are available from: http://www.cc.gatech. //
1369 // edu/projects/large_models/ply.html. Except the header section, ply file //
1370 // format has exactly the same format for listing vertices and polygons as //
1371 // off file format. //
1372 // //
1374 
1375 bool tetgenio::load_ply(char* filebasename)
1376 {
1377  FILE *fp;
1378  tetgenio::facet *f;
1379  tetgenio::polygon *p;
1380  char infilename[FILENAMESIZE];
1381  char buffer[INPUTLINESIZE];
1382  char *bufferp, *str;
1383  double *coord;
1384  int endheader = 0, format = 0;
1385  int nverts = 0, iverts = 0;
1386  int nfaces = 0, ifaces = 0;
1387  int line_count = 0, i;
1388 
1389  // Default, the ply file's index is from '0'. We check it by remembering the
1390  // smallest index we found in the file. It should be either 0 or 1.
1391  int smallestidx = 0;
1392 
1393  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1394  infilename[FILENAMESIZE - 1] = '\0';
1395  if (infilename[0] == '\0') {
1396  printf("Error: No filename.\n");
1397  return false;
1398  }
1399  if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1400  strcat(infilename, ".ply");
1401  }
1402 
1403  if (!(fp = fopen(infilename, "r"))) {
1404  printf("Error: Unable to open file %s\n", infilename);
1405  return false;
1406  }
1407  printf("Opening %s.\n", infilename);
1408 
1409  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1410  if (!endheader) {
1411  // Find if it is the keyword "end_header".
1412  str = strstr(bufferp, "end_header");
1413  // strstr() is case sensitive.
1414  if (!str) str = strstr(bufferp, "End_header");
1415  if (!str) str = strstr(bufferp, "End_Header");
1416  if (str) {
1417  // This is the end of the header section.
1418  endheader = 1;
1419  continue;
1420  }
1421  // Parse the number of vertices and the number of faces.
1422  if (nverts == 0 || nfaces == 0) {
1423  // Find if it si the keyword "element".
1424  str = strstr(bufferp, "element");
1425  if (!str) str = strstr(bufferp, "Element");
1426  if (str) {
1427  bufferp = findnextfield(str);
1428  if (*bufferp == '\0') {
1429  printf("Syntax error reading element type on line%d in file %s\n",
1430  line_count, infilename);
1431  fclose(fp);
1432  return false;
1433  }
1434  if (nverts == 0) {
1435  // Find if it is the keyword "vertex".
1436  str = strstr(bufferp, "vertex");
1437  if (!str) str = strstr(bufferp, "Vertex");
1438  if (str) {
1439  bufferp = findnextnumber(str);
1440  if (*bufferp == '\0') {
1441  printf("Syntax error reading vertex number on line");
1442  printf(" %d in file %s\n", line_count, infilename);
1443  fclose(fp);
1444  return false;
1445  }
1446  nverts = (int) strtol(bufferp, &bufferp, 0);
1447  // Allocate memory for 'tetgenio'
1448  if (nverts > 0) {
1449  numberofpoints = nverts;
1450  pointlist = new REAL[nverts * 3];
1451  smallestidx = nverts + 1; // A big enough index.
1452  }
1453  }
1454  }
1455  if (nfaces == 0) {
1456  // Find if it is the keyword "face".
1457  str = strstr(bufferp, "face");
1458  if (!str) str = strstr(bufferp, "Face");
1459  if (str) {
1460  bufferp = findnextnumber(str);
1461  if (*bufferp == '\0') {
1462  printf("Syntax error reading face number on line");
1463  printf(" %d in file %s\n", line_count, infilename);
1464  fclose(fp);
1465  return false;
1466  }
1467  nfaces = (int) strtol(bufferp, &bufferp, 0);
1468  // Allocate memory for 'tetgenio'
1469  if (nfaces > 0) {
1470  numberoffacets = nfaces;
1471  facetlist = new tetgenio::facet[nfaces];
1472  }
1473  }
1474  }
1475  } // It is not the string "element".
1476  }
1477  if (format == 0) {
1478  // Find the keyword "format".
1479  str = strstr(bufferp, "format");
1480  if (!str) str = strstr(bufferp, "Format");
1481  if (str) {
1482  format = 1;
1483  bufferp = findnextfield(str);
1484  // Find if it is the string "ascii".
1485  str = strstr(bufferp, "ascii");
1486  if (!str) str = strstr(bufferp, "ASCII");
1487  if (!str) {
1488  printf("This routine only reads ascii format of ply files.\n");
1489  printf("Hint: You can convert the binary to ascii format by\n");
1490  printf(" using the provided ply tools:\n");
1491  printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
1492  fclose(fp);
1493  return false;
1494  }
1495  }
1496  }
1497  } else if (iverts < nverts) {
1498  // Read vertex coordinates
1499  coord = &pointlist[iverts * 3];
1500  for (i = 0; i < 3; i++) {
1501  if (*bufferp == '\0') {
1502  printf("Syntax error reading vertex coords on line %d in file %s\n",
1503  line_count, infilename);
1504  fclose(fp);
1505  return false;
1506  }
1507  coord[i] = (REAL) strtod(bufferp, &bufferp);
1508  bufferp = findnextnumber(bufferp);
1509  }
1510  iverts++;
1511  } else if (ifaces < nfaces) {
1512  // Get next face
1513  f = &facetlist[ifaces];
1514  init(f);
1515  // In .off format, each facet has one polygon, no hole.
1516  f->numberofpolygons = 1;
1517  f->polygonlist = new tetgenio::polygon[1];
1518  p = &f->polygonlist[0];
1519  init(p);
1520  // Read the number of vertices, it should be greater than 0.
1521  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1522  if (p->numberofvertices == 0) {
1523  printf("Syntax error reading polygon on line %d in file %s\n",
1524  line_count, infilename);
1525  fclose(fp);
1526  return false;
1527  }
1528  // Allocate memory for face vertices
1529  p->vertexlist = new int[p->numberofvertices];
1530  for (i = 0; i < p->numberofvertices; i++) {
1531  bufferp = findnextnumber(bufferp);
1532  if (*bufferp == '\0') {
1533  printf("Syntax error reading polygon on line %d in file %s\n",
1534  line_count, infilename);
1535  fclose(fp);
1536  return false;
1537  }
1538  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1539  if (p->vertexlist[i] < smallestidx) {
1540  smallestidx = p->vertexlist[i];
1541  }
1542  }
1543  ifaces++;
1544  } else {
1545  // Should never get here
1546  printf("Found extra text starting at line %d in file %s\n", line_count,
1547  infilename);
1548  break;
1549  }
1550  }
1551 
1552  // Close file
1553  fclose(fp);
1554 
1555  // Decide the firstnumber of the index.
1556  if (smallestidx == 0) {
1557  firstnumber = 0;
1558  } else if (smallestidx == 1) {
1559  firstnumber = 1;
1560  } else {
1561  printf("A wrong smallest index (%d) was detected in file %s\n",
1562  smallestidx, infilename);
1563  return false;
1564  }
1565 
1566  if (iverts != nverts) {
1567  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1568  nverts, iverts, infilename);
1569  return false;
1570  }
1571  if (ifaces != nfaces) {
1572  printf("Expected %d faces, but read only %d faces in file %s\n",
1573  nfaces, ifaces, infilename);
1574  return false;
1575  }
1576 
1577  return true;
1578 }
1579 
1581 // //
1582 // load_stl() Load a surface mesh from a .stl file. //
1583 // //
1584 // The .stl or stereolithography format is an ASCII or binary file used in //
1585 // manufacturing. It is a list of the triangular surfaces that describe a //
1586 // computer generated solid model. This is the standard input for most rapid //
1587 // prototyping machines. //
1588 // //
1589 // Comment: A .stl file many contain many duplicated points. They will be //
1590 // unified during the Delaunay tetrahedralization process. //
1591 // //
1593 
1594 void SwapBytes(char *array, int size, int n)
1595 {
1596  char *x = new char[size];
1597  for(int i = 0; i < n; i++) {
1598  char *a = &array[i * size];
1599  memcpy(x, a, size);
1600  for(int c = 0; c < size; c++)
1601  a[size - 1 - c] = x[c];
1602  }
1603  delete [] x;
1604 }
1605 
1606 bool tetgenio::load_stl(char* filebasename)
1607 {
1608  FILE *fp;
1609  tetgenmesh::arraypool *plist;
1610  tetgenio::facet *f;
1611  tetgenio::polygon *p;
1612  char infilename[FILENAMESIZE];
1613  char buffer[INPUTLINESIZE];
1614  char *bufferp, *str;
1615  double *coord;
1616  int solid = 0;
1617  int nverts = 0, iverts = 0;
1618  int nfaces = 0;
1619  int line_count = 0, i;
1620 
1621  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1622  infilename[FILENAMESIZE - 1] = '\0';
1623  if (infilename[0] == '\0') {
1624  printf("Error: No filename.\n");
1625  return false;
1626  }
1627  if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1628  strcat(infilename, ".stl");
1629  }
1630 
1631  if (!(fp = fopen(infilename, "rb"))) {
1632  printf("Error: Unable to open file %s\n", infilename);
1633  return false;
1634  }
1635  printf("Opening %s.\n", infilename);
1636 
1637  // "solid", or binary data header
1638  if(!fgets(buffer, sizeof(buffer), fp)){ fclose(fp); return 0; }
1639  bool binary = strncmp(buffer, "solid", 5) && strncmp(buffer, "SOLID", 5);
1640 
1641  // STL file has no number of points available. Use a list to read points.
1642  plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10);
1643 
1644  if(!binary){
1645  solid = 1;
1646  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1647  // The ASCII .stl file must start with the lower case keyword solid and
1648  // end with endsolid.
1649  if (solid == 0) {
1650  // Read header
1651  bufferp = strstr(bufferp, "solid");
1652  if (bufferp != NULL) {
1653  solid = 1;
1654  }
1655  } else {
1656  // We're inside the block of the solid.
1657  str = bufferp;
1658  // Is this the end of the solid.
1659  bufferp = strstr(bufferp, "endsolid");
1660  if (bufferp != NULL) {
1661  solid = 0;
1662  } else {
1663  // Read the XYZ coordinates if it is a vertex.
1664  bufferp = str;
1665  bufferp = strstr(bufferp, "vertex");
1666  if (bufferp != NULL) {
1667  plist->newindex((void **) &coord);
1668  for (i = 0; i < 3; i++) {
1669  bufferp = findnextnumber(bufferp);
1670  if (*bufferp == '\0') {
1671  printf("Syntax error reading vertex coords on line %d\n",
1672  line_count);
1673  delete plist;
1674  fclose(fp);
1675  return false;
1676  }
1677  coord[i] = (REAL) strtod(bufferp, &bufferp);
1678  }
1679  }
1680  }
1681  }
1682  }
1683  } // if(!binary)
1684 
1685  else {
1686  rewind(fp);
1687  while(!feof(fp)) {
1688  char header[80];
1689  if(!fread(header, sizeof(char), 80, fp)) break;
1690  unsigned int nfacets = 0;
1691  size_t ret = fread(&nfacets, sizeof(unsigned int), 1, fp);
1692  bool swap = false;
1693  if(nfacets > 100000000){
1694  //Msg::Info("Swapping bytes from binary file");
1695  swap = true;
1696  SwapBytes((char*)&nfacets, sizeof(unsigned int), 1);
1697  }
1698  if(ret && nfacets){
1699  //points.resize(points.size() + 1);
1700  char *data = new char[nfacets * 50 * sizeof(char)];
1701  ret = fread(data, sizeof(char), nfacets * 50, fp);
1702  if(ret == nfacets * 50){
1703  for(unsigned int i = 0; i < nfacets; i++) {
1704  float *xyz = (float *)&data[i * 50 * sizeof(char)];
1705  if(swap) SwapBytes((char*)xyz, sizeof(float), 12);
1706  for(int j = 0; j < 3; j++){
1707  //SPoint3 p(xyz[3 + 3 * j], xyz[3 + 3 * j + 1], xyz[3 + 3 * j + 2]);
1708  //points.back().push_back(p);
1709  //bbox += p;
1710  plist->newindex((void **) &coord);
1711  coord[0] = xyz[3 + 3 * j];
1712  coord[1] = xyz[3 + 3 * j + 1];
1713  coord[2] = xyz[3 + 3 * j + 2];
1714  }
1715  }
1716  }
1717  delete [] data;
1718  }
1719  } // while (!feof(fp))
1720  } // binary
1721 
1722  fclose(fp);
1723 
1724  nverts = (int) plist->objects;
1725  // nverts should be an integer times 3 (every 3 vertices denote a face).
1726  if (nverts == 0 || (nverts % 3 != 0)) {
1727  printf("Error: Wrong number of vertices in file %s.\n", infilename);
1728  delete plist;
1729  return false;
1730  }
1731  numberofpoints = nverts;
1732  pointlist = new REAL[nverts * 3];
1733  for (i = 0; i < nverts; i++) {
1734  coord = (double *) fastlookup(plist, i);
1735  iverts = i * 3;
1736  pointlist[iverts] = (REAL) coord[0];
1737  pointlist[iverts + 1] = (REAL) coord[1];
1738  pointlist[iverts + 2] = (REAL) coord[2];
1739  }
1740 
1741  nfaces = (int) (nverts / 3);
1742  numberoffacets = nfaces;
1743  facetlist = new tetgenio::facet[nfaces];
1744 
1745  // Default use '1' as the array starting index.
1746  firstnumber = 1;
1747  iverts = firstnumber;
1748  for (i = 0; i < nfaces; i++) {
1749  f = &facetlist[i];
1750  init(f);
1751  // In .stl format, each facet has one polygon, no hole.
1752  f->numberofpolygons = 1;
1753  f->polygonlist = new tetgenio::polygon[1];
1754  p = &f->polygonlist[0];
1755  init(p);
1756  // Each polygon has three vertices.
1757  p->numberofvertices = 3;
1758  p->vertexlist = new int[p->numberofvertices];
1759  p->vertexlist[0] = iverts;
1760  p->vertexlist[1] = iverts + 1;
1761  p->vertexlist[2] = iverts + 2;
1762  iverts += 3;
1763  }
1764 
1765  delete plist;
1766  return true;
1767 }
1768 
1770 // //
1771 // load_medit() Load a surface mesh from a .mesh file. //
1772 // //
1773 // The .mesh format is the file format of Medit, a user-friendly interactive //
1774 // mesh viewer program. //
1775 // //
1777 
1778 bool tetgenio::load_medit(char* filebasename, int istetmesh)
1779 {
1780  FILE *fp;
1781  tetgenio::facet *tmpflist, *f;
1782  tetgenio::polygon *p;
1783  char infilename[FILENAMESIZE];
1784  char buffer[INPUTLINESIZE];
1785  char *bufferp, *str;
1786  double *coord;
1787  int *tmpfmlist;
1788  int dimension = 0;
1789  int nverts = 0;
1790  int nfaces = 0;
1791  int ntets = 0;
1792  int line_count = 0;
1793  int corners = 0; // 3 (triangle) or 4 (quad).
1794  int *plist;
1795  int i, j;
1796 
1797  int smallestidx = 0;
1798 
1799  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1800  infilename[FILENAMESIZE - 1] = '\0';
1801  if (infilename[0] == '\0') {
1802  printf("Error: No filename.\n");
1803  return false;
1804  }
1805  if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1806  strcat(infilename, ".mesh");
1807  }
1808 
1809  if (!(fp = fopen(infilename, "r"))) {
1810  printf("Error: Unable to open file %s\n", infilename);
1811  return false;
1812  }
1813  printf("Opening %s.\n", infilename);
1814 
1815  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1816  if (*bufferp == '#') continue; // A comment line is skipped.
1817  if (dimension == 0) {
1818  // Find if it is the keyword "Dimension".
1819  str = strstr(bufferp, "Dimension");
1820  if (!str) str = strstr(bufferp, "dimension");
1821  if (!str) str = strstr(bufferp, "DIMENSION");
1822  if (str) {
1823  // Read the dimensions
1824  bufferp = findnextnumber(str); // Skip field "Dimension".
1825  if (*bufferp == '\0') {
1826  // Read a non-empty line.
1827  bufferp = readline(buffer, fp, &line_count);
1828  }
1829  dimension = (int) strtol(bufferp, &bufferp, 0);
1830  if (dimension != 2 && dimension != 3) {
1831  printf("Unknown dimension in file on line %d in file %s\n",
1832  line_count, infilename);
1833  fclose(fp);
1834  return false;
1835  }
1836  mesh_dim = dimension;
1837  }
1838  }
1839  if (nverts == 0) {
1840  // Find if it is the keyword "Vertices".
1841  str = strstr(bufferp, "Vertices");
1842  if (!str) str = strstr(bufferp, "vertices");
1843  if (!str) str = strstr(bufferp, "VERTICES");
1844  if (str) {
1845  // Read the number of vertices.
1846  bufferp = findnextnumber(str); // Skip field "Vertices".
1847  if (*bufferp == '\0') {
1848  // Read a non-empty line.
1849  bufferp = readline(buffer, fp, &line_count);
1850  }
1851  nverts = (int) strtol(bufferp, &bufferp, 0);
1852  // Initialize the smallest index.
1853  smallestidx = nverts + 1;
1854  // Allocate memory for 'tetgenio'
1855  if (nverts > 0) {
1856  numberofpoints = nverts;
1857  pointlist = new REAL[nverts * 3];
1858  }
1859  // Read the follwoing node list.
1860  for (i = 0; i < nverts; i++) {
1861  bufferp = readline(buffer, fp, &line_count);
1862  if (bufferp == NULL) {
1863  printf("Unexpected end of file on line %d in file %s\n",
1864  line_count, infilename);
1865  fclose(fp);
1866  return false;
1867  }
1868  // Read vertex coordinates
1869  coord = &pointlist[i * 3];
1870  for (j = 0; j < 3; j++) {
1871  if (*bufferp == '\0') {
1872  printf("Syntax error reading vertex coords on line");
1873  printf(" %d in file %s\n", line_count, infilename);
1874  fclose(fp);
1875  return false;
1876  }
1877  if ((j < 2) || (dimension == 3)) {
1878  coord[j] = (REAL) strtod(bufferp, &bufferp);
1879  } else {
1880  coord[j] = 0.0;
1881  }
1882  bufferp = findnextnumber(bufferp);
1883  }
1884  }
1885  continue;
1886  }
1887  }
1888  if (ntets == 0) {
1889  // Find if it is the keyword "Tetrahedra"
1890  corners = 0;
1891  str = strstr(bufferp, "Tetrahedra");
1892  if (!str) str = strstr(bufferp, "tetrahedra");
1893  if (!str) str = strstr(bufferp, "TETRAHEDRA");
1894  if (str) {
1895  corners = 4;
1896  }
1897  if (corners == 4) {
1898  // Read the number of tetrahedra
1899  bufferp = findnextnumber(str); // Skip field "Tetrahedra".
1900  if (*bufferp == '\0') {
1901  // Read a non-empty line.
1902  bufferp = readline(buffer, fp, &line_count);
1903  }
1904  ntets = strtol(bufferp, &bufferp, 0);
1905  if (ntets > 0) {
1906  // It is a tetrahedral mesh.
1907  numberoftetrahedra = ntets;
1908  numberofcorners = 4;
1909  numberoftetrahedronattributes = 1;
1910  tetrahedronlist = new int[ntets * 4];
1911  tetrahedronattributelist = new REAL[ntets];
1912  }
1913  } // if (corners == 4)
1914  // Read the list of tetrahedra.
1915  for (i = 0; i < numberoftetrahedra; i++) {
1916  plist = &(tetrahedronlist[i * 4]);
1917  bufferp = readline(buffer, fp, &line_count);
1918  if (bufferp == NULL) {
1919  printf("Unexpected end of file on line %d in file %s\n",
1920  line_count, infilename);
1921  fclose(fp);
1922  return false;
1923  }
1924  // Read the vertices of the tet.
1925  for (j = 0; j < corners; j++) {
1926  if (*bufferp == '\0') {
1927  printf("Syntax error reading face on line %d in file %s\n",
1928  line_count, infilename);
1929  fclose(fp);
1930  return false;
1931  }
1932  plist[j] = (int) strtol(bufferp, &bufferp, 0);
1933  // Remember the smallest index.
1934  if (plist[j] < smallestidx) smallestidx = plist[j];
1935  bufferp = findnextnumber(bufferp);
1936  }
1937  // Read the attribute of the tet if it exists.
1938  tetrahedronattributelist[i] = 0;
1939  if (*bufferp != '\0') {
1940  tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
1941  }
1942  } // i
1943  } // Tetrahedra
1944  if (nfaces == 0) {
1945  // Find if it is the keyword "Triangles" or "Quadrilaterals".
1946  corners = 0;
1947  str = strstr(bufferp, "Triangles");
1948  if (!str) str = strstr(bufferp, "triangles");
1949  if (!str) str = strstr(bufferp, "TRIANGLES");
1950  if (str) {
1951  corners = 3;
1952  } else {
1953  str = strstr(bufferp, "Quadrilaterals");
1954  if (!str) str = strstr(bufferp, "quadrilaterals");
1955  if (!str) str = strstr(bufferp, "QUADRILATERALS");
1956  if (str) {
1957  corners = 4;
1958  }
1959  }
1960  if (corners == 3 || corners == 4) {
1961  // Read the number of triangles (or quadrilaterals).
1962  bufferp = findnextnumber(str); // Skip field "Triangles".
1963  if (*bufferp == '\0') {
1964  // Read a non-empty line.
1965  bufferp = readline(buffer, fp, &line_count);
1966  }
1967  nfaces = strtol(bufferp, &bufferp, 0);
1968  // Allocate memory for 'tetgenio'
1969  if (nfaces > 0) {
1970  if (!istetmesh) {
1971  // It is a PLC surface mesh.
1972  if (numberoffacets > 0) {
1973  // facetlist has already been allocated. Enlarge arrays.
1974  // This happens when the surface mesh contains mixed cells.
1975  tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1976  tmpfmlist = new int[numberoffacets + nfaces];
1977  // Copy the data of old arrays into new arrays.
1978  for (i = 0; i < numberoffacets; i++) {
1979  f = &(tmpflist[i]);
1980  tetgenio::init(f);
1981  *f = facetlist[i];
1982  tmpfmlist[i] = facetmarkerlist[i];
1983  }
1984  // Release old arrays.
1985  delete [] facetlist;
1986  delete [] facetmarkerlist;
1987  // Remember the new arrays.
1988  facetlist = tmpflist;
1989  facetmarkerlist = tmpfmlist;
1990  } else {
1991  // This is the first time to allocate facetlist.
1992  facetlist = new tetgenio::facet[nfaces];
1993  facetmarkerlist = new int[nfaces];
1994  }
1995  } else {
1996  if (corners == 3) {
1997  // It is a surface mesh of a tetrahedral mesh.
1998  numberoftrifaces = nfaces;
1999  trifacelist = new int[nfaces * 3];
2000  trifacemarkerlist = new int[nfaces];
2001  }
2002  }
2003  } // if (nfaces > 0)
2004  // Read the following list of faces.
2005  if (!istetmesh) {
2006  for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
2007  bufferp = readline(buffer, fp, &line_count);
2008  if (bufferp == NULL) {
2009  printf("Unexpected end of file on line %d in file %s\n",
2010  line_count, infilename);
2011  fclose(fp);
2012  return false;
2013  }
2014  f = &facetlist[i];
2015  tetgenio::init(f);
2016  // In .mesh format, each facet has one polygon, no hole.
2017  f->numberofpolygons = 1;
2018  f->polygonlist = new tetgenio::polygon[1];
2019  p = &f->polygonlist[0];
2020  tetgenio::init(p);
2021  p->numberofvertices = corners;
2022  // Allocate memory for face vertices
2023  p->vertexlist = new int[p->numberofvertices];
2024  // Read the vertices of the face.
2025  for (j = 0; j < corners; j++) {
2026  if (*bufferp == '\0') {
2027  printf("Syntax error reading face on line %d in file %s\n",
2028  line_count, infilename);
2029  fclose(fp);
2030  return false;
2031  }
2032  p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
2033  // Remember the smallest index.
2034  if (p->vertexlist[j] < smallestidx) {
2035  smallestidx = p->vertexlist[j];
2036  }
2037  bufferp = findnextnumber(bufferp);
2038  }
2039  // Read the marker of the face if it exists.
2040  facetmarkerlist[i] = 0;
2041  if (*bufferp != '\0') {
2042  facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2043  }
2044  }
2045  // Have read in a list of triangles/quads.
2046  numberoffacets += nfaces;
2047  nfaces = 0;
2048  } else {
2049  // It is a surface mesh of a tetrahedral mesh.
2050  if (corners == 3) {
2051  for (i = 0; i < numberoftrifaces; i++) {
2052  plist = &(trifacelist[i * 3]);
2053  bufferp = readline(buffer, fp, &line_count);
2054  if (bufferp == NULL) {
2055  printf("Unexpected end of file on line %d in file %s\n",
2056  line_count, infilename);
2057  fclose(fp);
2058  return false;
2059  }
2060  // Read the vertices of the face.
2061  for (j = 0; j < corners; j++) {
2062  if (*bufferp == '\0') {
2063  printf("Syntax error reading face on line %d in file %s\n",
2064  line_count, infilename);
2065  fclose(fp);
2066  return false;
2067  }
2068  plist[j] = (int) strtol(bufferp, &bufferp, 0);
2069  // Remember the smallest index.
2070  if (plist[j] < smallestidx) {
2071  smallestidx = plist[j];
2072  }
2073  bufferp = findnextnumber(bufferp);
2074  }
2075  // Read the marker of the face if it exists.
2076  trifacemarkerlist[i] = 0;
2077  if (*bufferp != '\0') {
2078  trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2079  }
2080  } // i
2081  } // if (corners == 3)
2082  } // if (b->refine)
2083  } // if (corners == 3 || corners == 4)
2084  }
2085  }
2086 
2087  // Close file
2088  fclose(fp);
2089 
2090  // Decide the firstnumber of the index.
2091  if (smallestidx == 0) {
2092  firstnumber = 0;
2093  } else if (smallestidx == 1) {
2094  firstnumber = 1;
2095  } else {
2096  printf("A wrong smallest index (%d) was detected in file %s\n",
2097  smallestidx, infilename);
2098  return false;
2099  }
2100 
2101  return true;
2102 }
2103 
2105 // //
2106 // load_vtk() Load VTK surface mesh from file (.vtk ascii or binary). //
2107 // //
2108 // This function is contributed by: Bryn Lloyd, Computer Vision Laboratory, //
2109 // ETH, Zuerich. May 7, 2007. //
2110 // //
2112 
2113 // Two inline functions used in read/write VTK files.
2114 
2115 void swapBytes(unsigned char* var, int size)
2116 {
2117  int i = 0;
2118  int j = size - 1;
2119  char c;
2120 
2121  while (i < j) {
2122  c = var[i]; var[i] = var[j]; var[j] = c;
2123  i++, j--;
2124  }
2125 }
2126 
2127 bool testIsBigEndian()
2128 {
2129  short word = 0x4321;
2130  if((*(char *)& word) != 0x21)
2131  return true;
2132  else
2133  return false;
2134 }
2135 
2136 bool tetgenio::load_vtk(char* filebasename)
2137 {
2138  FILE *fp;
2139  tetgenio::facet *f;
2140  tetgenio::polygon *p;
2141  char infilename[FILENAMESIZE];
2142  char line[INPUTLINESIZE];
2143  char mode[128], id[256], fmt[64];
2144  char *bufferp;
2145  double *coord;
2146  float _x, _y, _z;
2147  int nverts = 0;
2148  int nfaces = 0;
2149  int line_count = 0;
2150  int dummy;
2151  int id1, id2, id3;
2152  int nn = -1;
2153  int nn_old = -1;
2154  int i, j;
2155  bool ImALittleEndian = !testIsBigEndian();
2156 
2157  int smallestidx = 0;
2158 
2159  strncpy(infilename, filebasename, FILENAMESIZE - 1);
2160  infilename[FILENAMESIZE - 1] = '\0';
2161  if (infilename[0] == '\0') {
2162  printf("Error: No filename.\n");
2163  return false;
2164  }
2165  if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
2166  strcat(infilename, ".vtk");
2167  }
2168  if (!(fp = fopen(infilename, "r"))) {
2169  printf("Error: Unable to open file %s\n", infilename);
2170  return false;
2171  }
2172  printf("Opening %s.\n", infilename);
2173 
2174  // Default uses the index starts from '0'.
2175  firstnumber = 0;
2176  strcpy(mode, "BINARY");
2177 
2178  while((bufferp = readline(line, fp, &line_count)) != NULL) {
2179  if(strlen(line) == 0) continue;
2180  //swallow lines beginning with a comment sign or white space
2181  if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 ||
2182  line[0] == 32) continue;
2183 
2184  sscanf(line, "%s", id);
2185  if(!strcmp(id, "ASCII")) {
2186  strcpy(mode, "ASCII");
2187  }
2188 
2189  if(!strcmp(id, "POINTS")) {
2190  sscanf(line, "%s %d %s", id, &nverts, fmt);
2191  if (nverts > 0) {
2192  numberofpoints = nverts;
2193  pointlist = new REAL[nverts * 3];
2194  smallestidx = nverts + 1;
2195  }
2196 
2197  if(!strcmp(mode, "BINARY")) {
2198  for(i = 0; i < nverts; i++) {
2199  coord = &pointlist[i * 3];
2200  if(!strcmp(fmt, "double")) {
2201  fread((char*)(&(coord[0])), sizeof(double), 1, fp);
2202  fread((char*)(&(coord[1])), sizeof(double), 1, fp);
2203  fread((char*)(&(coord[2])), sizeof(double), 1, fp);
2204  if(ImALittleEndian){
2205  swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
2206  swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
2207  swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
2208  }
2209  } else if(!strcmp(fmt, "float")) {
2210  fread((char*)(&_x), sizeof(float), 1, fp);
2211  fread((char*)(&_y), sizeof(float), 1, fp);
2212  fread((char*)(&_z), sizeof(float), 1, fp);
2213  if(ImALittleEndian){
2214  swapBytes((unsigned char *) &_x, sizeof(_x));
2215  swapBytes((unsigned char *) &_y, sizeof(_y));
2216  swapBytes((unsigned char *) &_z, sizeof(_z));
2217  }
2218  coord[0] = double(_x);
2219  coord[1] = double(_y);
2220  coord[2] = double(_z);
2221  } else {
2222  printf("Error: Only float or double formats are supported!\n");
2223  return false;
2224  }
2225  }
2226  } else if(!strcmp(mode, "ASCII")) {
2227  for(i = 0; i < nverts; i++){
2228  bufferp = readline(line, fp, &line_count);
2229  if (bufferp == NULL) {
2230  printf("Unexpected end of file on line %d in file %s\n",
2231  line_count, infilename);
2232  fclose(fp);
2233  return false;
2234  }
2235  // Read vertex coordinates
2236  coord = &pointlist[i * 3];
2237  for (j = 0; j < 3; j++) {
2238  if (*bufferp == '\0') {
2239  printf("Syntax error reading vertex coords on line");
2240  printf(" %d in file %s\n", line_count, infilename);
2241  fclose(fp);
2242  return false;
2243  }
2244  coord[j] = (REAL) strtod(bufferp, &bufferp);
2245  bufferp = findnextnumber(bufferp);
2246  }
2247  }
2248  }
2249  continue;
2250  }
2251 
2252  if(!strcmp(id, "POLYGONS")) {
2253  sscanf(line, "%s %d %d", id, &nfaces, &dummy);
2254  if (nfaces > 0) {
2255  numberoffacets = nfaces;
2256  facetlist = new tetgenio::facet[nfaces];
2257  }
2258 
2259  if(!strcmp(mode, "BINARY")) {
2260  for(i = 0; i < nfaces; i++){
2261  fread((char*)(&nn), sizeof(int), 1, fp);
2262  if(ImALittleEndian){
2263  swapBytes((unsigned char *) &nn, sizeof(nn));
2264  }
2265  if (i == 0)
2266  nn_old = nn;
2267  if (nn != nn_old) {
2268  printf("Error: No mixed cells are allowed.\n");
2269  return false;
2270  }
2271 
2272  if(nn == 3){
2273  fread((char*)(&id1), sizeof(int), 1, fp);
2274  fread((char*)(&id2), sizeof(int), 1, fp);
2275  fread((char*)(&id3), sizeof(int), 1, fp);
2276  if(ImALittleEndian){
2277  swapBytes((unsigned char *) &id1, sizeof(id1));
2278  swapBytes((unsigned char *) &id2, sizeof(id2));
2279  swapBytes((unsigned char *) &id3, sizeof(id3));
2280  }
2281  f = &facetlist[i];
2282  init(f);
2283  // In .off format, each facet has one polygon, no hole.
2284  f->numberofpolygons = 1;
2285  f->polygonlist = new tetgenio::polygon[1];
2286  p = &f->polygonlist[0];
2287  init(p);
2288  // Set number of vertices
2289  p->numberofvertices = 3;
2290  // Allocate memory for face vertices
2291  p->vertexlist = new int[p->numberofvertices];
2292  p->vertexlist[0] = id1;
2293  p->vertexlist[1] = id2;
2294  p->vertexlist[2] = id3;
2295  // Detect the smallest index.
2296  for (j = 0; j < 3; j++) {
2297  if (p->vertexlist[j] < smallestidx) {
2298  smallestidx = p->vertexlist[j];
2299  }
2300  }
2301  } else {
2302  printf("Error: Only triangles are supported\n");
2303  return false;
2304  }
2305  }
2306  } else if(!strcmp(mode, "ASCII")) {
2307  for(i = 0; i < nfaces; i++) {
2308  bufferp = readline(line, fp, &line_count);
2309  nn = (int) strtol(bufferp, &bufferp, 0);
2310  if (i == 0)
2311  nn_old = nn;
2312  if (nn != nn_old) {
2313  printf("Error: No mixed cells are allowed.\n");
2314  return false;
2315  }
2316 
2317  if (nn == 3) {
2318  bufferp = findnextnumber(bufferp); // Skip the first field.
2319  id1 = (int) strtol(bufferp, &bufferp, 0);
2320  bufferp = findnextnumber(bufferp);
2321  id2 = (int) strtol(bufferp, &bufferp, 0);
2322  bufferp = findnextnumber(bufferp);
2323  id3 = (int) strtol(bufferp, &bufferp, 0);
2324  f = &facetlist[i];
2325  init(f);
2326  // In .off format, each facet has one polygon, no hole.
2327  f->numberofpolygons = 1;
2328  f->polygonlist = new tetgenio::polygon[1];
2329  p = &f->polygonlist[0];
2330  init(p);
2331  // Set number of vertices
2332  p->numberofvertices = 3;
2333  // Allocate memory for face vertices
2334  p->vertexlist = new int[p->numberofvertices];
2335  p->vertexlist[0] = id1;
2336  p->vertexlist[1] = id2;
2337  p->vertexlist[2] = id3;
2338  // Detect the smallest index.
2339  for (j = 0; j < 3; j++) {
2340  if (p->vertexlist[j] < smallestidx) {
2341  smallestidx = p->vertexlist[j];
2342  }
2343  }
2344  } else {
2345  printf("Error: Only triangles are supported.\n");
2346  return false;
2347  }
2348  }
2349  }
2350 
2351  fclose(fp);
2352 
2353  // Decide the firstnumber of the index.
2354  if (smallestidx == 0) {
2355  firstnumber = 0;
2356  } else if (smallestidx == 1) {
2357  firstnumber = 1;
2358  } else {
2359  printf("A wrong smallest index (%d) was detected in file %s\n",
2360  smallestidx, infilename);
2361  return false;
2362  }
2363 
2364  return true;
2365  }
2366 
2367  if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
2368  printf("Warning: load_vtk(): cannot read formats LINES, CELLS.\n");
2369  }
2370  } // while ()
2371 
2372  return true;
2373 }
2374 
2376 // //
2377 // load_plc() Load a piecewise linear complex from file(s). //
2378 // //
2380 
2381 bool tetgenio::load_plc(char* filebasename, int object)
2382 {
2383  bool success;
2384 
2385  if (object == (int) tetgenbehavior::NODES) {
2386  success = load_node(filebasename);
2387  } else if (object == (int) tetgenbehavior::POLY) {
2388  success = load_poly(filebasename);
2389  } else if (object == (int) tetgenbehavior::OFF) {
2390  success = load_off(filebasename);
2391  } else if (object == (int) tetgenbehavior::PLY) {
2392  success = load_ply(filebasename);
2393  } else if (object == (int) tetgenbehavior::STL) {
2394  success = load_stl(filebasename);
2395  } else if (object == (int) tetgenbehavior::MEDIT) {
2396  success = load_medit(filebasename, 0);
2397  } else if (object == (int) tetgenbehavior::VTK) {
2398  success = load_vtk(filebasename);
2399  } else {
2400  success = load_poly(filebasename);
2401  }
2402 
2403  if (success) {
2404  // Try to load the following files (.edge, .var, .mtr).
2405  load_edge(filebasename);
2406  load_var(filebasename);
2407  load_mtr(filebasename);
2408  }
2409 
2410  return success;
2411 }
2412 
2414 // //
2415 // load_mesh() Load a tetrahedral mesh from file(s). //
2416 // //
2418 
2419 bool tetgenio::load_tetmesh(char* filebasename, int object)
2420 {
2421  bool success;
2422 
2423  if (object == (int) tetgenbehavior::MEDIT) {
2424  success = load_medit(filebasename, 1);
2425  } else if (object == (int) tetgenbehavior::NEU_MESH) {
2426  //success = load_neumesh(filebasename, 1);
2427  } else {
2428  success = load_node(filebasename);
2429  if (success) {
2430  success = load_tet(filebasename);
2431  }
2432  if (success) {
2433  // Try to load the following files (.face, .edge, .vol).
2434  load_face(filebasename);
2435  load_edge(filebasename);
2436  load_vol(filebasename);
2437  }
2438  }
2439 
2440  //if (success) {
2441  // Try to load the following files (.var, .mtr).
2442  load_var(filebasename);
2443  load_mtr(filebasename);
2444  //}
2445 
2446  return success;
2447 }
2448 
2450 // //
2451 // save_nodes() Save points to a .node file. //
2452 // //
2454 
2455 void tetgenio::save_nodes(char* filebasename)
2456 {
2457  FILE *fout;
2458  char outnodefilename[FILENAMESIZE];
2459  char outmtrfilename[FILENAMESIZE];
2460  int i, j;
2461 
2462  sprintf(outnodefilename, "%s.node", filebasename);
2463  printf("Saving nodes to %s\n", outnodefilename);
2464  fout = fopen(outnodefilename, "w");
2465  fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
2466  numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
2467  for (i = 0; i < numberofpoints; i++) {
2468  if (mesh_dim == 2) {
2469  fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 3],
2470  pointlist[i * 3 + 1]);
2471  } else {
2472  fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
2473  pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2474  }
2475  for (j = 0; j < numberofpointattributes; j++) {
2476  fprintf(fout, " %.16g",
2477  pointattributelist[i * numberofpointattributes + j]);
2478  }
2479  if (pointmarkerlist != NULL) {
2480  fprintf(fout, " %d", pointmarkerlist[i]);
2481  }
2482  fprintf(fout, "\n");
2483  }
2484  fclose(fout);
2485 
2486  // If the point metrics exist, output them to a .mtr file.
2487  if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
2488  sprintf(outmtrfilename, "%s.mtr", filebasename);
2489  printf("Saving metrics to %s\n", outmtrfilename);
2490  fout = fopen(outmtrfilename, "w");
2491  fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
2492  for (i = 0; i < numberofpoints; i++) {
2493  for (j = 0; j < numberofpointmtrs; j++) {
2494  fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2495  }
2496  fprintf(fout, "\n");
2497  }
2498  fclose(fout);
2499  }
2500 }
2501 
2503 // //
2504 // save_elements() Save elements to a .ele file. //
2505 // //
2507 
2508 void tetgenio::save_elements(char* filebasename)
2509 {
2510  FILE *fout;
2511  char outelefilename[FILENAMESIZE];
2512  int i, j;
2513 
2514  sprintf(outelefilename, "%s.ele", filebasename);
2515  printf("Saving elements to %s\n", outelefilename);
2516  fout = fopen(outelefilename, "w");
2517  if (mesh_dim == 3) {
2518  fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
2519  numberoftetrahedronattributes);
2520  for (i = 0; i < numberoftetrahedra; i++) {
2521  fprintf(fout, "%d", i + firstnumber);
2522  for (j = 0; j < numberofcorners; j++) {
2523  fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
2524  }
2525  for (j = 0; j < numberoftetrahedronattributes; j++) {
2526  fprintf(fout, " %g",
2527  tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2528  }
2529  fprintf(fout, "\n");
2530  }
2531  } else {
2532  // Save a two-dimensional mesh.
2533  fprintf(fout, "%d %d %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
2534  for (i = 0; i < numberoftrifaces; i++) {
2535  fprintf(fout, "%d", i + firstnumber);
2536  for (j = 0; j < 3; j++) {
2537  fprintf(fout, " %5d", trifacelist[i * 3 + j]);
2538  }
2539  if (trifacemarkerlist != NULL) {
2540  fprintf(fout, " %d", trifacemarkerlist[i]);
2541  }
2542  fprintf(fout, "\n");
2543  }
2544  }
2545 
2546  fclose(fout);
2547 }
2548 
2550 // //
2551 // save_faces() Save faces to a .face file. //
2552 // //
2554 
2555 void tetgenio::save_faces(char* filebasename)
2556 {
2557  FILE *fout;
2558  char outfacefilename[FILENAMESIZE];
2559  int i;
2560 
2561  sprintf(outfacefilename, "%s.face", filebasename);
2562  printf("Saving faces to %s\n", outfacefilename);
2563  fout = fopen(outfacefilename, "w");
2564  fprintf(fout, "%d %d\n", numberoftrifaces,
2565  trifacemarkerlist != NULL ? 1 : 0);
2566  for (i = 0; i < numberoftrifaces; i++) {
2567  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
2568  trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2569  if (trifacemarkerlist != NULL) {
2570  fprintf(fout, " %d", trifacemarkerlist[i]);
2571  }
2572  fprintf(fout, "\n");
2573  }
2574 
2575  fclose(fout);
2576 }
2577 
2579 // //
2580 // save_edges() Save egdes to a .edge file. //
2581 // //
2583 
2584 void tetgenio::save_edges(char* filebasename)
2585 {
2586  FILE *fout;
2587  char outedgefilename[FILENAMESIZE];
2588  int i;
2589 
2590  sprintf(outedgefilename, "%s.edge", filebasename);
2591  printf("Saving edges to %s\n", outedgefilename);
2592  fout = fopen(outedgefilename, "w");
2593  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2594  for (i = 0; i < numberofedges; i++) {
2595  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2596  edgelist[i * 2 + 1]);
2597  if (edgemarkerlist != NULL) {
2598  fprintf(fout, " %d", edgemarkerlist[i]);
2599  }
2600  fprintf(fout, "\n");
2601  }
2602 
2603  fclose(fout);
2604 }
2605 
2607 // //
2608 // save_neighbors() Save egdes to a .neigh file. //
2609 // //
2611 
2612 void tetgenio::save_neighbors(char* filebasename)
2613 {
2614  FILE *fout;
2615  char outneighborfilename[FILENAMESIZE];
2616  int i;
2617 
2618  sprintf(outneighborfilename, "%s.neigh", filebasename);
2619  printf("Saving neighbors to %s\n", outneighborfilename);
2620  fout = fopen(outneighborfilename, "w");
2621  fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
2622  for (i = 0; i < numberoftetrahedra; i++) {
2623  if (mesh_dim == 2) {
2624  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
2625  neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2626  } else {
2627  fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
2628  neighborlist[i * 4], neighborlist[i * 4 + 1],
2629  neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2630  }
2631  fprintf(fout, "\n");
2632  }
2633 
2634  fclose(fout);
2635 }
2636 
2638 // //
2639 // save_poly() Save segments or facets to a .poly file. //
2640 // //
2641 // It only save the facets, holes and regions. No .node file is saved. //
2642 // //
2644 
2645 void tetgenio::save_poly(char* filebasename)
2646 {
2647  FILE *fout;
2648  facet *f;
2649  polygon *p;
2650  char outpolyfilename[FILENAMESIZE];
2651  int i, j, k;
2652 
2653  sprintf(outpolyfilename, "%s.poly", filebasename);
2654  printf("Saving poly to %s\n", outpolyfilename);
2655  fout = fopen(outpolyfilename, "w");
2656 
2657  // The zero indicates that the vertices are in a separate .node file.
2658  // Followed by number of dimensions, number of vertex attributes,
2659  // and number of boundary markers (zero or one).
2660  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2661  pointmarkerlist != NULL ? 1 : 0);
2662 
2663  // Save segments or facets.
2664  if (mesh_dim == 2) {
2665  // Number of segments, number of boundary markers (zero or one).
2666  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2667  for (i = 0; i < numberofedges; i++) {
2668  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2669  edgelist[i * 2 + 1]);
2670  if (edgemarkerlist != NULL) {
2671  fprintf(fout, " %d", edgemarkerlist[i]);
2672  }
2673  fprintf(fout, "\n");
2674  }
2675  } else {
2676  // Number of facets, number of boundary markers (zero or one).
2677  fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
2678  for (i = 0; i < numberoffacets; i++) {
2679  f = &(facetlist[i]);
2680  fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
2681  facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
2682  // Output polygons of this facet.
2683  for (j = 0; j < f->numberofpolygons; j++) {
2684  p = &(f->polygonlist[j]);
2685  fprintf(fout, "%d ", p->numberofvertices);
2686  for (k = 0; k < p->numberofvertices; k++) {
2687  if (((k + 1) % 10) == 0) {
2688  fprintf(fout, "\n ");
2689  }
2690  fprintf(fout, " %d", p->vertexlist[k]);
2691  }
2692  fprintf(fout, "\n");
2693  }
2694  // Output holes of this facet.
2695  for (j = 0; j < f->numberofholes; j++) {
2696  fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
2697  f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2698  }
2699  }
2700  }
2701 
2702  // Save holes.
2703  fprintf(fout, "%d\n", numberofholes);
2704  for (i = 0; i < numberofholes; i++) {
2705  // Output x, y coordinates.
2706  fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
2707  holelist[i * mesh_dim + 1]);
2708  if (mesh_dim == 3) {
2709  // Output z coordinate.
2710  fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
2711  }
2712  fprintf(fout, "\n");
2713  }
2714 
2715  // Save regions.
2716  fprintf(fout, "%d\n", numberofregions);
2717  for (i = 0; i < numberofregions; i++) {
2718  if (mesh_dim == 2) {
2719  // Output the index, x, y coordinates, attribute (region number)
2720  // and maximum area constraint (maybe -1).
2721  fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
2722  regionlist[i * 4], regionlist[i * 4 + 1],
2723  regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2724  } else {
2725  // Output the index, x, y, z coordinates, attribute (region number)
2726  // and maximum volume constraint (maybe -1).
2727  fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
2728  regionlist[i * 5], regionlist[i * 5 + 1],
2729  regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2730  regionlist[i * 5 + 4]);
2731  }
2732  }
2733 
2734  fclose(fout);
2735 }
2736 
2738 // //
2739 // save_faces2smesh() Save triangular faces to a .smesh file. //
2740 // //
2741 // It only save the facets. No holes and regions. No .node file. //
2742 // //
2744 
2745 void tetgenio::save_faces2smesh(char* filebasename)
2746 {
2747  FILE *fout;
2748  char outsmeshfilename[FILENAMESIZE];
2749  int i, j;
2750 
2751  sprintf(outsmeshfilename, "%s.smesh", filebasename);
2752  printf("Saving faces to %s\n", outsmeshfilename);
2753  fout = fopen(outsmeshfilename, "w");
2754 
2755  // The zero indicates that the vertices are in a separate .node file.
2756  // Followed by number of dimensions, number of vertex attributes,
2757  // and number of boundary markers (zero or one).
2758  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2759  pointmarkerlist != NULL ? 1 : 0);
2760 
2761  // Number of facets, number of boundary markers (zero or one).
2762  fprintf(fout, "%d %d\n", numberoftrifaces,
2763  trifacemarkerlist != NULL ? 1 : 0);
2764 
2765  // Output triangular facets.
2766  for (i = 0; i < numberoftrifaces; i++) {
2767  j = i * 3;
2768  fprintf(fout, "3 %d %d %d", trifacelist[j], trifacelist[j + 1],
2769  trifacelist[j + 2]);
2770  if (trifacemarkerlist != NULL) {
2771  fprintf(fout, " %d", trifacemarkerlist[i]);
2772  }
2773  fprintf(fout, "\n");
2774  }
2775 
2776  // No holes and regions.
2777  fprintf(fout, "0\n");
2778  fprintf(fout, "0\n");
2779 
2780  fclose(fout);
2781 }
2782 
2784 // //
2785 // readline() Read a nonempty line from a file. //
2786 // //
2787 // A line is considered "nonempty" if it contains something more than white //
2788 // spaces. If a line is considered empty, it will be dropped and the next //
2789 // line will be read, this process ends until reaching the end-of-file or a //
2790 // non-empty line. Return NULL if it is the end-of-file, otherwise, return //
2791 // a pointer to the first non-whitespace character of the line. //
2792 // //
2794 
2795 char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2796 {
2797  char *result;
2798 
2799  // Search for a non-empty line.
2800  do {
2801  result = fgets(string, INPUTLINESIZE - 1, infile);
2802  if (linenumber) (*linenumber)++;
2803  if (result == (char *) NULL) {
2804  return (char *) NULL;
2805  }
2806  // Skip white spaces.
2807  while ((*result == ' ') || (*result == '\t')) result++;
2808  // If it's end of line, read another line and try again.
2809  } while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
2810  return result;
2811 }
2812 
2814 // //
2815 // findnextfield() Find the next field of a string. //
2816 // //
2817 // Jumps past the current field by searching for whitespace or a comma, then //
2818 // jumps past the whitespace or the comma to find the next field. //
2819 // //
2821 
2822 char* tetgenio::findnextfield(char *string)
2823 {
2824  char *result;
2825 
2826  result = string;
2827  // Skip the current field. Stop upon reaching whitespace or a comma.
2828  while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
2829  (*result != ',') && (*result != ';')) {
2830  result++;
2831  }
2832  // Now skip the whitespace or the comma, stop at anything else that looks
2833  // like a character, or the end of a line.
2834  while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2835  (*result == ';')) {
2836  result++;
2837  }
2838  return result;
2839 }
2840 
2842 // //
2843 // readnumberline() Read a nonempty number line from a file. //
2844 // //
2845 // A line is considered "nonempty" if it contains something that looks like //
2846 // a number. Comments (prefaced by `#') are ignored. //
2847 // //
2849 
2850 char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2851 {
2852  char *result;
2853 
2854  // Search for something that looks like a number.
2855  do {
2856  result = fgets(string, INPUTLINESIZE, infile);
2857  if (result == (char *) NULL) {
2858  return result;
2859  }
2860  // Skip anything that doesn't look like a number, a comment,
2861  // or the end of a line.
2862  while ((*result != '\0') && (*result != '#')
2863  && (*result != '.') && (*result != '+') && (*result != '-')
2864  && ((*result < '0') || (*result > '9'))) {
2865  result++;
2866  }
2867  // If it's a comment or end of line, read another line and try again.
2868  } while ((*result == '#') || (*result == '\0'));
2869  return result;
2870 }
2871 
2873 // //
2874 // findnextnumber() Find the next field of a number string. //
2875 // //
2876 // Jumps past the current field by searching for whitespace or a comma, then //
2877 // jumps past the whitespace or the comma to find the next field that looks //
2878 // like a number. //
2879 // //
2881 
2882 char* tetgenio::findnextnumber(char *string)
2883 {
2884  char *result;
2885 
2886  result = string;
2887  // Skip the current field. Stop upon reaching whitespace or a comma.
2888  while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2889  (*result != '\t') && (*result != ',')) {
2890  result++;
2891  }
2892  // Now skip the whitespace and anything else that doesn't look like a
2893  // number, a comment, or the end of a line.
2894  while ((*result != '\0') && (*result != '#')
2895  && (*result != '.') && (*result != '+') && (*result != '-')
2896  && ((*result < '0') || (*result > '9'))) {
2897  result++;
2898  }
2899  // Check for a comment (prefixed with `#').
2900  if (*result == '#') {
2901  *result = '\0';
2902  }
2903  return result;
2904 }
2905 
2909 
2910 
2914 
2916 // //
2917 // syntax() Print list of command line switches. //
2918 // //
2920 
2921 void tetgenbehavior::syntax()
2922 {
2923  printf(" tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
2924  printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
2925  printf(" -Y Preserves the input surface mesh (does not modify it).\n");
2926  printf(" -r Reconstructs a previously generated mesh.\n");
2927  printf(" -q Refines mesh (to improve mesh quality).\n");
2928  printf(" -R Mesh coarsening (to reduce the mesh elements).\n");
2929  printf(" -A Assigns attributes to tetrahedra in different regions.\n");
2930  printf(" -a Applies a maximum tetrahedron volume constraint.\n");
2931  printf(" -m Applies a mesh sizing function.\n");
2932  printf(" -i Inserts a list of additional points.\n");
2933  printf(" -O Specifies the level of mesh optimization.\n");
2934  printf(" -S Specifies maximum number of added points.\n");
2935  printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
2936  printf(" -X Suppresses use of exact arithmetic.\n");
2937  printf(" -M No merge of coplanar facets or very close vertices.\n");
2938  printf(" -w Generates weighted Delaunay (regular) triangulation.\n");
2939  printf(" -c Retains the convex hull of the PLC.\n");
2940  printf(" -d Detects self-intersections of facets of the PLC.\n");
2941  printf(" -z Numbers all output items starting from zero.\n");
2942  printf(" -f Outputs all faces to .face file.\n");
2943  printf(" -e Outputs all edges to .edge file.\n");
2944  printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
2945  printf(" -v Outputs Voronoi diagram to files.\n");
2946  printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
2947  printf(" -k Outputs mesh to .vtk file for viewing by Paraview.\n");
2948  printf(" -J No jettison of unused vertices from output .node file.\n");
2949  printf(" -B Suppresses output of boundary information.\n");
2950  printf(" -N Suppresses output of .node file.\n");
2951  printf(" -E Suppresses output of .ele file.\n");
2952  printf(" -F Suppresses output of .face and .edge file.\n");
2953  printf(" -I Suppresses mesh iteration numbers.\n");
2954  printf(" -C Checks the consistency of the final mesh.\n");
2955  printf(" -Q Quiet: No terminal output except errors.\n");
2956  printf(" -V Verbose: Detailed information, more terminal output.\n");
2957  printf(" -h Help: A brief instruction for using TetGen.\n");
2958 }
2959 
2961 // //
2962 // usage() Print a brief instruction for using TetGen. //
2963 // //
2965 
2966 void tetgenbehavior::usage()
2967 {
2968  printf("TetGen\n");
2969  printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
2970  printf("Triangulator\n");
2971  printf("Version 1.5\n");
2972  printf("August 18, 2018\n");
2973  printf("\n");
2974  printf("Copyright (C) 2002 - 2018\n");
2975  printf("\n");
2976  printf("What Can TetGen Do?\n");
2977  printf("\n");
2978  printf(" TetGen generates Delaunay tetrahedralizations, constrained\n");
2979  printf(" Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
2980  printf("\n");
2981  printf("Command Line Syntax:\n");
2982  printf("\n");
2983  printf(" Below is the basic command line syntax of TetGen with a list of ");
2984  printf("short\n");
2985  printf(" descriptions. Underscores indicate that numbers may optionally\n");
2986  printf(" follow certain switches. Do not leave any space between a ");
2987  printf("switch\n");
2988  printf(" and its numeric parameter. \'input_file\' contains input data\n");
2989  printf(" depending on the switches you supplied which may be a ");
2990  printf(" piecewise\n");
2991  printf(" linear complex or a list of nodes. File formats and detailed\n");
2992  printf(" description of command line switches are found in user's ");
2993  printf("manual.\n");
2994  printf("\n");
2995  syntax();
2996  printf("\n");
2997  printf("Examples of How to Use TetGen:\n");
2998  printf("\n");
2999  printf(" \'tetgen object\' reads vertices from object.node, and writes ");
3000  printf("their\n Delaunay tetrahedralization to object.1.node, ");
3001  printf("object.1.ele\n (tetrahedra), and object.1.face");
3002  printf(" (convex hull faces).\n");
3003  printf("\n");
3004  printf(" \'tetgen -p object\' reads a PLC from object.poly or object.");
3005  printf("smesh (and\n possibly object.node) and writes its constrained ");
3006  printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele, ");
3007  printf("object.1.face,\n");
3008  printf(" (boundary faces) and object.1.edge (boundary edges).\n");
3009  printf("\n");
3010  printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
3011  printf(" object.smesh (and possibly object.node), generates a mesh ");
3012  printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and ");
3013  printf("have volume\n of 0.1 or less, and writes the mesh to ");
3014  printf("object.1.node, object.1.ele,\n object.1.face, and object.1.edge\n");
3015  printf("\n");
3016  printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
3017  terminatetetgen(NULL, 0);
3018 }
3019 
3021 // //
3022 // parse_commandline() Read the command line, identify switches, and set //
3023 // up options and file names. //
3024 // //
3025 // 'argc' and 'argv' are the same parameters passed to the function main() //
3026 // of a C/C++ program. They together represent the command line user invoked //
3027 // from an environment in which TetGen is running. //
3028 // //
3030 
3031 bool tetgenbehavior::parse_commandline(int argc, char **argv)
3032 {
3033  int startindex;
3034  int increment;
3035  int meshnumber;
3036  int i, j, k;
3037  char workstring[1024];
3038 
3039  // First determine the input style of the switches.
3040  if (argc == 0) {
3041  startindex = 0; // Switches are given without a dash.
3042  argc = 1; // For running the following for-loop once.
3043  commandline[0] = '\0';
3044  } else {
3045  startindex = 1;
3046  strcpy(commandline, argv[0]);
3047  strcat(commandline, " ");
3048  }
3049 
3050  for (i = startindex; i < argc; i++) {
3051  // Remember the command line for output.
3052  strcat(commandline, argv[i]);
3053  strcat(commandline, " ");
3054  if (startindex == 1) {
3055  // Is this string a filename?
3056  if (argv[i][0] != '-') {
3057  strncpy(infilename, argv[i], 1024 - 1);
3058  infilename[1024 - 1] = '\0';
3059  continue;
3060  }
3061  }
3062  // Parse the individual switch from the string.
3063  for (j = startindex; argv[i][j] != '\0'; j++) {
3064  if (argv[i][j] == 'p') {
3065  plc = 1;
3066  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3067  (argv[i][j + 1] == '.')) {
3068  k = 0;
3069  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3070  (argv[i][j + 1] == '.')) {
3071  j++;
3072  workstring[k] = argv[i][j];
3073  k++;
3074  }
3075  workstring[k] = '\0';
3076  facet_separate_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3077  }
3078  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3079  j++;
3080  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3081  (argv[i][j + 1] == '.')) {
3082  k = 0;
3083  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3084  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3085  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3086  j++;
3087  workstring[k] = argv[i][j];
3088  k++;
3089  }
3090  workstring[k] = '\0';
3091  facet_overlap_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3092  }
3093  }
3094  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3095  j++;
3096  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3097  (argv[i][j + 1] == '.')) {
3098  k = 0;
3099  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3100  (argv[i][j + 1] == '.')) {
3101  j++;
3102  workstring[k] = argv[i][j];
3103  k++;
3104  }
3105  workstring[k] = '\0';
3106  facet_small_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3107  }
3108  }
3109  } else if (argv[i][j] == 's') {
3110  psc = 1;
3111  } else if (argv[i][j] == 'Y') {
3112  nobisect = 1;
3113  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3114  nobisect_nomerge = (argv[i][j + 1] - '0');
3115  j++;
3116  }
3117  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3118  j++;
3119  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3120  supsteiner_level = (argv[i][j + 1] - '0');
3121  j++;
3122  }
3123  }
3124  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3125  j++;
3126  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3127  addsteiner_algo = (argv[i][j + 1] - '0');
3128  j++;
3129  }
3130  }
3131  } else if (argv[i][j] == 'r') {
3132  refine = 1;
3133  } else if (argv[i][j] == 'q') {
3134  quality = 1;
3135  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3136  (argv[i][j + 1] == '.')) {
3137  k = 0;
3138  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3139  (argv[i][j + 1] == '.')) {
3140  j++;
3141  workstring[k] = argv[i][j];
3142  k++;
3143  }
3144  workstring[k] = '\0';
3145  minratio = (REAL) strtod(workstring, (char **) NULL);
3146  }
3147  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3148  j++;
3149  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3150  (argv[i][j + 1] == '.')) {
3151  k = 0;
3152  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3153  (argv[i][j + 1] == '.')) {
3154  j++;
3155  workstring[k] = argv[i][j];
3156  k++;
3157  }
3158  workstring[k] = '\0';
3159  mindihedral = (REAL) strtod(workstring, (char **) NULL);
3160  }
3161  }
3162  } else if (argv[i][j] == 'R') {
3163  coarsen = 1;
3164  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3165  coarsen_param = (argv[i][j + 1] - '0');
3166  j++;
3167  }
3168  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3169  j++;
3170  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3171  (argv[i][j + 1] == '.')) {
3172  k = 0;
3173  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3174  (argv[i][j + 1] == '.')) {
3175  j++;
3176  workstring[k] = argv[i][j];
3177  k++;
3178  }
3179  workstring[k] = '\0';
3180  coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
3181  }
3182  }
3183  } else if (argv[i][j] == 'w') {
3184  weighted = 1;
3185  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3186  weighted_param = (argv[i][j + 1] - '0');
3187  j++;
3188  }
3189  } else if (argv[i][j] == 'b') {
3190  // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
3191  brio_hilbert = 1;
3192  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3193  (argv[i][j + 1] == '.')) {
3194  k = 0;
3195  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3196  (argv[i][j + 1] == '.')) {
3197  j++;
3198  workstring[k] = argv[i][j];
3199  k++;
3200  }
3201  workstring[k] = '\0';
3202  brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
3203  }
3204  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3205  j++;
3206  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3207  (argv[i][j + 1] == '.')) {
3208  k = 0;
3209  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3210  (argv[i][j + 1] == '.')) {
3211  j++;
3212  workstring[k] = argv[i][j];
3213  k++;
3214  }
3215  workstring[k] = '\0';
3216  brio_ratio = (REAL) strtod(workstring, (char **) NULL);
3217  }
3218  }
3219  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3220  j++;
3221  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3222  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3223  k = 0;
3224  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3225  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3226  j++;
3227  workstring[k] = argv[i][j];
3228  k++;
3229  }
3230  workstring[k] = '\0';
3231  hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
3232  }
3233  }
3234  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3235  j++;
3236  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3237  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3238  k = 0;
3239  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3240  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3241  j++;
3242  workstring[k] = argv[i][j];
3243  k++;
3244  }
3245  workstring[k] = '\0';
3246  hilbert_order = (REAL) strtod(workstring, (char **) NULL);
3247  }
3248  }
3249  if (brio_threshold == 0) { // -b0
3250  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3251  }
3252  if (brio_ratio >= 1.0) { // -b/1
3253  no_sort = 1;
3254  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3255  }
3256  } else if (argv[i][j] == 'l') {
3257  incrflip = 1;
3258  } else if (argv[i][j] == 'L') {
3259  flipinsert = 1;
3260  } else if (argv[i][j] == 'm') {
3261  metric = 1;
3262  } else if (argv[i][j] == 'a') {
3263  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3264  (argv[i][j + 1] == '.')) {
3265  fixedvolume = 1;
3266  k = 0;
3267  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3268  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3269  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3270  j++;
3271  workstring[k] = argv[i][j];
3272  k++;
3273  }
3274  workstring[k] = '\0';
3275  maxvolume = (REAL) strtod(workstring, (char **) NULL);
3276  } else {
3277  varvolume = 1;
3278  }
3279  } else if (argv[i][j] == 'A') {
3280  regionattrib = 1;
3281  } else if (argv[i][j] == 'D') {
3282  cdtrefine = 1;
3283  if (argv[i][j + 1] == 'l') {
3284  use_equatorial_lens = 1;
3285  } else if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
3286  reflevel = (argv[i][j + 1] - '1') + 1;
3287  j++;
3288  }
3289  } else if (argv[i][j] == 'i') {
3290  insertaddpoints = 1;
3291  } else if (argv[i][j] == 'd') {
3292  diagnose = 1;
3293  } else if (argv[i][j] == 'c') {
3294  convex = 1;
3295  } else if (argv[i][j] == 'M') {
3296  nomergefacet = 1;
3297  nomergevertex = 1;
3298  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3299  nomergefacet = (argv[i][j + 1] - '0');
3300  j++;
3301  }
3302  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3303  j++;
3304  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3305  nomergevertex = (argv[i][j + 1] - '0');
3306  j++;
3307  }
3308  }
3309  } else if (argv[i][j] == 'X') {
3310  if (argv[i][j + 1] == '1') {
3311  nostaticfilter = 1;
3312  j++;
3313  } else {
3314  noexact = 1;
3315  }
3316  } else if (argv[i][j] == 'z') {
3317  if (argv[i][j + 1] == '1') { // -z1
3318  reversetetori = 1;
3319  j++;
3320  } else {
3321  zeroindex = 1; // -z
3322  }
3323  } else if (argv[i][j] == 'f') {
3324  facesout++;
3325  } else if (argv[i][j] == 'e') {
3326  edgesout++;
3327  } else if (argv[i][j] == 'n') {
3328  neighout++;
3329  } else if (argv[i][j] == 'v') {
3330  voroout = 1;
3331  } else if (argv[i][j] == 'g') {
3332  meditview = 1;
3333  } else if (argv[i][j] == 'k') {
3334  vtkview = 1;
3335  } else if (argv[i][j] == 'J') {
3336  nojettison = 1;
3337  } else if (argv[i][j] == 'B') {
3338  nobound = 1;
3339  } else if (argv[i][j] == 'N') {
3340  nonodewritten = 1;
3341  } else if (argv[i][j] == 'E') {
3342  noelewritten = 1;
3343  } else if (argv[i][j] == 'F') {
3344  nofacewritten = 1;
3345  } else if (argv[i][j] == 'I') {
3346  noiterationnum = 1;
3347  } else if (argv[i][j] == 'S') {
3348  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3349  (argv[i][j + 1] == '.')) {
3350  k = 0;
3351  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3352  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3353  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3354  j++;
3355  workstring[k] = argv[i][j];
3356  k++;
3357  }
3358  workstring[k] = '\0';
3359  steinerleft = (int) strtol(workstring, (char **) NULL, 0);
3360  }
3361  } else if (argv[i][j] == 'o') {
3362  if (argv[i][j + 1] == '2') {
3363  order = 2;
3364  j++;
3365  }
3366  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3367  j++;
3368  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3369  (argv[i][j + 1] == '.')) {
3370  k = 0;
3371  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3372  (argv[i][j + 1] == '.')) {
3373  j++;
3374  workstring[k] = argv[i][j];
3375  k++;
3376  }
3377  workstring[k] = '\0';
3378  optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
3379  }
3380  }
3381  } else if (argv[i][j] == 'O') {
3382  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3383  optlevel = (argv[i][j + 1] - '0');
3384  j++;
3385  }
3386  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3387  j++;
3388  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
3389  optscheme = (argv[i][j + 1] - '0');
3390  j++;
3391  }
3392  }
3393  } else if (argv[i][j] == 'T') {
3394  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3395  (argv[i][j + 1] == '.')) {
3396  k = 0;
3397  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3398  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3399  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3400  j++;
3401  workstring[k] = argv[i][j];
3402  k++;
3403  }
3404  workstring[k] = '\0';
3405  epsilon = (REAL) strtod(workstring, (char **) NULL);
3406  }
3407  } else if (argv[i][j] == 'C') {
3408  docheck++;
3409  } else if (argv[i][j] == 'Q') {
3410  quiet = 1;
3411  } else if (argv[i][j] == 'V') {
3412  verbose++;
3413  } else if (argv[i][j] == 'x') {
3414  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3415  (argv[i][j + 1] == '.')) {
3416  k = 0;
3417  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3418  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3419  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3420  j++;
3421  workstring[k] = argv[i][j];
3422  k++;
3423  }
3424  workstring[k] = '\0';
3425  tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
3426  if (tetrahedraperblock > 8188) {
3427  vertexperblock = tetrahedraperblock / 2;
3428  shellfaceperblock = vertexperblock / 2;
3429  } else {
3430  tetrahedraperblock = 8188;
3431  }
3432  }
3433  } else if (argv[i][j] == 'H') {
3434  if (argv[i+1][0] != '-') {
3435  hole_mesh = 1;
3436  // It is a filename following by -H
3437  strncpy(hole_mesh_filename, argv[i+1], 1024 - 1);
3438  hole_mesh_filename[1024 - 1] = '\0';
3439  i++; // Skip the next string.
3440  break; // j
3441  }
3442  } else if (argv[i][j] == 'K') {
3443  apply_flow_bc = 1;
3444  } else if ((argv[i][j] == 'h') || // (argv[i][j] == 'H')
3445  (argv[i][j] == '?')) {
3446  usage();
3447  } else {
3448  printf("Warning: Unknown switch -%c.\n", argv[i][j]);
3449  }
3450  }
3451  }
3452 
3453  if (startindex == 0) {
3454  // Set a temporary filename for debugging output.
3455  strcpy(infilename, "tetgen-tmpfile");
3456  } else {
3457  if (infilename[0] == '\0') {
3458  // No input file name. Print the syntax and exit.
3459  syntax();
3460  terminatetetgen(NULL, 0);
3461  }
3462  // Recognize the object from file extension if it is available.
3463  if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3464  infilename[strlen(infilename) - 5] = '\0';
3465  object = NODES;
3466  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3467  infilename[strlen(infilename) - 5] = '\0';
3468  object = POLY;
3469  plc = 1;
3470  } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3471  infilename[strlen(infilename) - 6] = '\0';
3472  object = POLY;
3473  plc = 1;
3474  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3475  infilename[strlen(infilename) - 4] = '\0';
3476  object = OFF;
3477  plc = 1;
3478  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3479  infilename[strlen(infilename) - 4] = '\0';
3480  object = PLY;
3481  plc = 1;
3482  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3483  infilename[strlen(infilename) - 4] = '\0';
3484  object = STL;
3485  plc = 1;
3486  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3487  infilename[strlen(infilename) - 5] = '\0';
3488  object = MEDIT;
3489  if (!refine) plc = 1;
3490  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
3491  infilename[strlen(infilename) - 4] = '\0';
3492  object = VTK;
3493  plc = 1;
3494  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3495  infilename[strlen(infilename) - 4] = '\0';
3496  object = MESH;
3497  refine = 1;
3498  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".neu")) {
3499  infilename[strlen(infilename) - 4] = '\0';
3500  object = NEU_MESH;
3501  refine = 1;
3502  }
3503  }
3504 
3505  if (nobisect && (!plc && !refine)) { // -Y
3506  plc = 1; // Default -p option.
3507  }
3508  if (quality && (!plc && !refine)) { // -q
3509  plc = 1; // Default -p option.
3510  }
3511  if (diagnose && !plc) { // -d
3512  plc = 1;
3513  }
3514  if (refine && !quality) { // -r only
3515  // Reconstruct a mesh, no mesh optimization.
3516  optlevel = 0;
3517  }
3518  if (insertaddpoints && (optlevel == 0)) { // with -i option
3519  optlevel = 2;
3520  }
3521  if (coarsen && (optlevel == 0)) { // with -R option
3522  optlevel = 2;
3523  }
3524 
3525  // Detect improper combinations of switches.
3526  if ((refine || plc) && weighted) {
3527  printf("Error: Switches -w cannot use together with -p or -r.\n");
3528  return false;
3529  }
3530 
3531  if (convex) { // -c
3532  if (plc && !regionattrib) {
3533  // -A (region attribute) is needed for marking exterior tets (-1).
3534  regionattrib = 1;
3535  }
3536  }
3537 
3538  // Note: -A must not used together with -r option.
3539  // Be careful not to add an extra attribute to each element unless the
3540  // input supports it (PLC in, but not refining a preexisting mesh).
3541  if (refine || !plc) {
3542  regionattrib = 0;
3543  }
3544  // Be careful not to allocate space for element area constraints that
3545  // will never be assigned any value (other than the default -1.0).
3546  if (!refine && !plc) {
3547  varvolume = 0;
3548  }
3549  // If '-a' or '-aa' is in use, enable '-q' option too.
3550  if (fixedvolume || varvolume) {
3551  if (quality == 0) {
3552  quality = 1;
3553  if (!plc && !refine) {
3554  plc = 1; // enable -p.
3555  }
3556  }
3557  }
3558  // No user-specified dihedral angle bound. Use default ones.
3559  if (!quality) {
3560  if (optmaxdihedral < 179.0) {
3561  if (nobisect) { // with -Y option
3562  optmaxdihedral = 179.0;
3563  } else { // -p only
3564  optmaxdihedral = 179.999;
3565  }
3566  }
3567  if (optminsmtdihed < 179.999) {
3568  optminsmtdihed = 179.999;
3569  }
3570  if (optminslidihed < 179.999) {
3571  optminslidihed = 179.999;
3572  }
3573  }
3574 
3575  increment = 0;
3576  strcpy(workstring, infilename);
3577  j = 1;
3578  while (workstring[j] != '\0') {
3579  if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
3580  increment = j + 1;
3581  }
3582  j++;
3583  }
3584  meshnumber = 0;
3585  if (increment > 0) {
3586  j = increment;
3587  do {
3588  if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
3589  meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
3590  } else {
3591  increment = 0;
3592  }
3593  j++;
3594  } while (workstring[j] != '\0');
3595  }
3596  if (noiterationnum) {
3597  strcpy(outfilename, infilename);
3598  } else if (increment == 0) {
3599  strcpy(outfilename, infilename);
3600  strcat(outfilename, ".1");
3601  } else {
3602  workstring[increment] = '%';
3603  workstring[increment + 1] = 'd';
3604  workstring[increment + 2] = '\0';
3605  sprintf(outfilename, workstring, meshnumber + 1);
3606  }
3607  // Additional input file name has the end ".a".
3608  strcpy(addinfilename, infilename);
3609  strcat(addinfilename, ".a");
3610  // Background filename has the form "*.b.ele", "*.b.node", ...
3611  strcpy(bgmeshfilename, infilename);
3612  strcat(bgmeshfilename, ".b");
3613 
3614  return true;
3615 }
3616 
3620 
3624 
3625 // Initialize fast lookup tables for mesh maniplulation primitives.
3626 
3627 int tetgenmesh::bondtbl[12][12] = {{0,},};
3628 int tetgenmesh::enexttbl[12] = {0,};
3629 int tetgenmesh::eprevtbl[12] = {0,};
3630 int tetgenmesh::enextesymtbl[12] = {0,};
3631 int tetgenmesh::eprevesymtbl[12] = {0,};
3632 int tetgenmesh::eorgoppotbl[12] = {0,};
3633 int tetgenmesh::edestoppotbl[12] = {0,};
3634 int tetgenmesh::fsymtbl[12][12] = {{0,},};
3635 int tetgenmesh::facepivot1[12] = {0,};
3636 int tetgenmesh::facepivot2[12][12] = {{0,},};
3637 int tetgenmesh::tsbondtbl[12][6] = {{0,},};
3638 int tetgenmesh::stbondtbl[12][6] = {{0,},};
3639 int tetgenmesh::tspivottbl[12][6] = {{0,},};
3640 int tetgenmesh::stpivottbl[12][6] = {{0,},};
3641 
3642 // Table 'esymtbl' takes an directed edge (version) as input, returns the
3643 // inversed edge (version) of it.
3644 
3645 int tetgenmesh::esymtbl[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
3646 
3647 // The following four tables give the 12 permutations of the set {0,1,2,3}.
3648 // An offset 4 is added to each element for a direct access of the points
3649 // in the tetrahedron data structure.
3650 
3651 int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
3652 int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
3653 int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
3654 int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
3655 
3656 // The twelve versions correspond to six undirected edges. The following two
3657 // tables map a version to an undirected edge and vice versa.
3658 
3659 int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
3660 int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
3661 
3662 // Edge versions whose apex or opposite may be dummypoint.
3663 
3664 int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
3665 
3666 
3667 // Table 'snextpivot' takes an edge version as input, returns the next edge
3668 // version in the same edge ring.
3669 
3670 int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
3671 
3672 // The following three tables give the 6 permutations of the set {0,1,2}.
3673 // An offset 3 is added to each element for a direct access of the points
3674 // in the triangle data structure.
3675 
3676 int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
3677 int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
3678 int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
3679 
3681 // //
3682 // inittable() Initialize the look-up tables. //
3683 // //
3685 
3686 void tetgenmesh::inittables()
3687 {
3688  int soffset, toffset;
3689  int i, j;
3690 
3691 
3692  // i = t1.ver; j = t2.ver;
3693  for (i = 0; i < 12; i++) {
3694  for (j = 0; j < 12; j++) {
3695  bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
3696  }
3697  }
3698 
3699 
3700  // i = t1.ver; j = t2.ver
3701  for (i = 0; i < 12; i++) {
3702  for (j = 0; j < 12; j++) {
3703  fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
3704  }
3705  }
3706 
3707 
3708  for (i = 0; i < 12; i++) {
3709  facepivot1[i] = (esymtbl[i] & 3);
3710  }
3711 
3712  for (i = 0; i < 12; i++) {
3713  for (j = 0; j < 12; j++) {
3714  facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
3715  }
3716  }
3717 
3718  for (i = 0; i < 12; i++) {
3719  enexttbl[i] = (i + 4) % 12;
3720  eprevtbl[i] = (i + 8) % 12;
3721  }
3722 
3723  for (i = 0; i < 12; i++) {
3724  enextesymtbl[i] = esymtbl[enexttbl[i]];
3725  eprevesymtbl[i] = esymtbl[eprevtbl[i]];
3726  }
3727 
3728  for (i = 0; i < 12; i++) {
3729  eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]];
3730  edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]];
3731  }
3732 
3733  // i = t.ver, j = s.shver
3734  for (i = 0; i < 12; i++) {
3735  for (j = 0; j < 6; j++) {
3736  if ((j & 1) == 0) {
3737  soffset = (6 - ((i & 12) >> 1)) % 6;
3738  toffset = (12 - ((j & 6) << 1)) % 12;
3739  } else {
3740  soffset = (i & 12) >> 1;
3741  toffset = (j & 6) << 1;
3742  }
3743  tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3744  stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3745  }
3746  }
3747 
3748 
3749  // i = t.ver, j = s.shver
3750  for (i = 0; i < 12; i++) {
3751  for (j = 0; j < 6; j++) {
3752  if ((j & 1) == 0) {
3753  soffset = (i & 12) >> 1;
3754  toffset = (j & 6) << 1;
3755  } else {
3756  soffset = (6 - ((i & 12) >> 1)) % 6;
3757  toffset = (12 - ((j & 6) << 1)) % 12;
3758  }
3759  tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3760  stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3761  }
3762  }
3763 }
3764 
3765 
3767 // //
3768 // restart() Deallocate all objects in this pool. //
3769 // //
3770 // The pool returns to a fresh state, like after it was initialized, except //
3771 // that no memory is freed to the operating system. Rather, the previously //
3772 // allocated blocks are ready to be used. //
3773 // //
3775 
3776 void tetgenmesh::arraypool::restart()
3777 {
3778  objects = 0l;
3779 }
3780 
3782 // //
3783 // poolinit() Initialize an arraypool for allocation of objects. //
3784 // //
3785 // Before the pool may be used, it must be initialized by this procedure. //
3786 // After initialization, memory can be allocated and freed in this pool. //
3787 // //
3789 
3790 void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
3791 {
3792  // Each object must be at least one byte long.
3793  objectbytes = sizeofobject > 1 ? sizeofobject : 1;
3794 
3795  log2objectsperblock = log2objperblk;
3796  // Compute the number of objects in each block.
3797  objectsperblock = ((int) 1) << log2objectsperblock;
3798  objectsperblockmark = objectsperblock - 1;
3799 
3800  // No memory has been allocated.
3801  totalmemory = 0l;
3802  // The top array has not been allocated yet.
3803  toparray = (char **) NULL;
3804  toparraylen = 0;
3805 
3806  // Ready all indices to be allocated.
3807  restart();
3808 }
3809 
3811 // //
3812 // arraypool() The constructor and destructor. //
3813 // //
3815 
3816 tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
3817 {
3818  poolinit(sizeofobject, log2objperblk);
3819 }
3820 
3821 tetgenmesh::arraypool::~arraypool()
3822 {
3823  int i;
3824 
3825  // Has anything been allocated at all?
3826  if (toparray != (char **) NULL) {
3827  // Walk through the top array.
3828  for (i = 0; i < toparraylen; i++) {
3829  // Check every pointer; NULLs may be scattered randomly.
3830  if (toparray[i] != (char *) NULL) {
3831  // Free an allocated block.
3832  free((void *) toparray[i]);
3833  }
3834  }
3835  // Free the top array.
3836  free((void *) toparray);
3837  }
3838 
3839  // The top array is no longer allocated.
3840  toparray = (char **) NULL;
3841  toparraylen = 0;
3842  objects = 0;
3843  totalmemory = 0;
3844 }
3845 
3847 // //
3848 // getblock() Return (and perhaps create) the block containing the object //
3849 // with a given index. //
3850 // //
3851 // This function takes care of allocating or resizing the top array if nece- //
3852 // ssary, and of allocating the block if it hasn't yet been allocated. //
3853 // //
3854 // Return a pointer to the beginning of the block (NOT the object). //
3855 // //
3857 
3858 char* tetgenmesh::arraypool::getblock(int objectindex)
3859 {
3860  char **newarray;
3861  char *block;
3862  int newsize;
3863  int topindex;
3864  int i;
3865 
3866  // Compute the index in the top array (upper bits).
3867  topindex = objectindex >> log2objectsperblock;
3868  // Does the top array need to be allocated or resized?
3869  if (toparray == (char **) NULL) {
3870  // Allocate the top array big enough to hold 'topindex', and NULL out
3871  // its contents.
3872  newsize = topindex + 128;
3873  toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3874  toparraylen = newsize;
3875  for (i = 0; i < newsize; i++) {
3876  toparray[i] = (char *) NULL;
3877  }
3878  // Account for the memory.
3879  totalmemory = newsize * (uintptr_t) sizeof(char *);
3880  } else if (topindex >= toparraylen) {
3881  // Resize the top array, making sure it holds 'topindex'.
3882  newsize = 3 * toparraylen;
3883  if (topindex >= newsize) {
3884  newsize = topindex + 128;
3885  }
3886  // Allocate the new array, copy the contents, NULL out the rest, and
3887  // free the old array.
3888  newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3889  for (i = 0; i < toparraylen; i++) {
3890  newarray[i] = toparray[i];
3891  }
3892  for (i = toparraylen; i < newsize; i++) {
3893  newarray[i] = (char *) NULL;
3894  }
3895  free(toparray);
3896  // Account for the memory.
3897  totalmemory += (newsize - toparraylen) * sizeof(char *);
3898  toparray = newarray;
3899  toparraylen = newsize;
3900  }
3901 
3902  // Find the block, or learn that it hasn't been allocated yet.
3903  block = toparray[topindex];
3904  if (block == (char *) NULL) {
3905  // Allocate a block at this index.
3906  block = (char *) malloc((size_t) (objectsperblock * objectbytes));
3907  toparray[topindex] = block;
3908  // Account for the memory.
3909  totalmemory += objectsperblock * objectbytes;
3910  }
3911 
3912  // Return a pointer to the block.
3913  return block;
3914 }
3915 
3917 // //
3918 // lookup() Return the pointer to the object with a given index, or NULL //
3919 // if the object's block doesn't exist yet. //
3920 // //
3922 
3923 void* tetgenmesh::arraypool::lookup(int objectindex)
3924 {
3925  char *block;
3926  int topindex;
3927 
3928  // Has the top array been allocated yet?
3929  if (toparray == (char **) NULL) {
3930  return (void *) NULL;
3931  }
3932 
3933  // Compute the index in the top array (upper bits).
3934  topindex = objectindex >> log2objectsperblock;
3935  // Does the top index fit in the top array?
3936  if (topindex >= toparraylen) {
3937  return (void *) NULL;
3938  }
3939 
3940  // Find the block, or learn that it hasn't been allocated yet.
3941  block = toparray[topindex];
3942  if (block == (char *) NULL) {
3943  return (void *) NULL;
3944  }
3945 
3946  // Compute a pointer to the object with the given index. Note that
3947  // 'objectsperblock' is a power of two, so the & operation is a bit mask
3948  // that preserves the lower bits.
3949  return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
3950 }
3951 
3953 // //
3954 // newindex() Allocate space for a fresh object from the pool. //
3955 // //
3956 // 'newptr' returns a pointer to the new object (it must not be a NULL). //
3957 // //
3959 
3960 int tetgenmesh::arraypool::newindex(void **newptr)
3961 {
3962  // Allocate an object at index 'firstvirgin'.
3963  int newindex = objects;
3964  *newptr = (void *) (getblock(objects) +
3965  (objects & (objectsperblock - 1)) * objectbytes);
3966  objects++;
3967 
3968  return newindex;
3969 }
3970 
3971 
3973 // //
3974 // memorypool() The constructors of memorypool. //
3975 // //
3977 
3978 tetgenmesh::memorypool::memorypool()
3979 {
3980  firstblock = nowblock = (void **) NULL;
3981  nextitem = (void *) NULL;
3982  deaditemstack = (void *) NULL;
3983  pathblock = (void **) NULL;
3984  pathitem = (void *) NULL;
3985  alignbytes = 0;
3986  itembytes = itemwords = 0;
3987  itemsperblock = 0;
3988  items = maxitems = 0l;
3989  unallocateditems = 0;
3990  pathitemsleft = 0;
3991 }
3992 
3993 tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize,
3994  int alignment)
3995 {
3996  poolinit(bytecount, itemcount, wsize, alignment);
3997 }
3998 
4000 // //
4001 // ~memorypool() Free to the operating system all memory taken by a pool. //
4002 // //
4004 
4005 tetgenmesh::memorypool::~memorypool()
4006 {
4007  while (firstblock != (void **) NULL) {
4008  nowblock = (void **) *(firstblock);
4009  free(firstblock);
4010  firstblock = nowblock;
4011  }
4012 }
4013 
4015 // //
4016 // poolinit() Initialize a pool of memory for allocation of items. //
4017 // //
4018 // A `pool' is created whose records have size at least `bytecount'. Items //
4019 // will be allocated in `itemcount'-item blocks. Each item is assumed to be //
4020 // a collection of words, and either pointers or floating-point values are //
4021 // assumed to be the "primary" word type. (The "primary" word type is used //
4022 // to determine alignment of items.) If `alignment' isn't zero, all items //
4023 // will be `alignment'-byte aligned in memory. `alignment' must be either a //
4024 // multiple or a factor of the primary word size; powers of two are safe. //
4025 // `alignment' is normally used to create a few unused bits at the bottom of //
4026 // each item's pointer, in which information may be stored. //
4027 // //
4029 
4030 void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
4031  int alignment)
4032 {
4033  // Find the proper alignment, which must be at least as large as:
4034  // - The parameter `alignment'.
4035  // - The primary word type, to avoid unaligned accesses.
4036  // - sizeof(void *), so the stack of dead items can be maintained
4037  // without unaligned accesses.
4038  if (alignment > wordsize) {
4039  alignbytes = alignment;
4040  } else {
4041  alignbytes = wordsize;
4042  }
4043  if ((int) sizeof(void *) > alignbytes) {
4044  alignbytes = (int) sizeof(void *);
4045  }
4046  itemwords = ((bytecount + alignbytes - 1) / alignbytes)
4047  * (alignbytes / wordsize);
4048  itembytes = itemwords * wordsize;
4049  itemsperblock = itemcount;
4050 
4051  // Allocate a block of items. Space for `itemsperblock' items and one
4052  // pointer (to point to the next block) are allocated, as well as space
4053  // to ensure alignment of the items.
4054  firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4055  + alignbytes);
4056  if (firstblock == (void **) NULL) {
4057  terminatetetgen(NULL, 1);
4058  }
4059  // Set the next block pointer to NULL.
4060  *(firstblock) = (void *) NULL;
4061  restart();
4062 }
4063 
4065 // //
4066 // restart() Deallocate all items in this pool. //
4067 // //
4068 // The pool is returned to its starting state, except that no memory is //
4069 // freed to the operating system. Rather, the previously allocated blocks //
4070 // are ready to be reused. //
4071 // //
4073 
4074 void tetgenmesh::memorypool::restart()
4075 {
4076  uintptr_t alignptr;
4077 
4078  items = 0;
4079  maxitems = 0;
4080 
4081  // Set the currently active block.
4082  nowblock = firstblock;
4083  // Find the first item in the pool. Increment by the size of (void *).
4084  alignptr = (uintptr_t) (nowblock + 1);
4085  // Align the item on an `alignbytes'-byte boundary.
4086  nextitem = (void *)
4087  (alignptr + (uintptr_t) alignbytes -
4088  (alignptr % (uintptr_t) alignbytes));
4089  // There are lots of unallocated items left in this block.
4090  unallocateditems = itemsperblock;
4091  // The stack of deallocated items is empty.
4092  deaditemstack = (void *) NULL;
4093 }
4094 
4096 // //
4097 // alloc() Allocate space for an item. //
4098 // //
4100 
4101 void* tetgenmesh::memorypool::alloc()
4102 {
4103  void *newitem;
4104  void **newblock;
4105  uintptr_t alignptr;
4106 
4107  // First check the linked list of dead items. If the list is not
4108  // empty, allocate an item from the list rather than a fresh one.
4109  if (deaditemstack != (void *) NULL) {
4110  newitem = deaditemstack; // Take first item in list.
4111  deaditemstack = * (void **) deaditemstack;
4112  } else {
4113  // Check if there are any free items left in the current block.
4114  if (unallocateditems == 0) {
4115  // Check if another block must be allocated.
4116  if (*nowblock == (void *) NULL) {
4117  // Allocate a new block of items, pointed to by the previous block.
4118  newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4119  + alignbytes);
4120  if (newblock == (void **) NULL) {
4121  terminatetetgen(NULL, 1);
4122  }
4123  *nowblock = (void *) newblock;
4124  // The next block pointer is NULL.
4125  *newblock = (void *) NULL;
4126  }
4127  // Move to the new block.
4128  nowblock = (void **) *nowblock;
4129  // Find the first item in the block.
4130  // Increment by the size of (void *).
4131  alignptr = (uintptr_t) (nowblock + 1);
4132  // Align the item on an `alignbytes'-byte boundary.
4133  nextitem = (void *)
4134  (alignptr + (uintptr_t) alignbytes -
4135  (alignptr % (uintptr_t) alignbytes));
4136  // There are lots of unallocated items left in this block.
4137  unallocateditems = itemsperblock;
4138  }
4139  // Allocate a new item.
4140  newitem = nextitem;
4141  // Advance `nextitem' pointer to next free item in block.
4142  nextitem = (void *) ((uintptr_t) nextitem + itembytes);
4143  unallocateditems--;
4144  maxitems++;
4145  }
4146  items++;
4147  return newitem;
4148 }
4149 
4151 // //
4152 // dealloc() Deallocate space for an item. //
4153 // //
4154 // The deallocated space is stored in a queue for later reuse. //
4155 // //
4157 
4158 void tetgenmesh::memorypool::dealloc(void *dyingitem)
4159 {
4160  // Push freshly killed item onto stack.
4161  *((void **) dyingitem) = deaditemstack;
4162  deaditemstack = dyingitem;
4163  items--;
4164 }
4165 
4167 // //
4168 // traversalinit() Prepare to traverse the entire list of items. //
4169 // //
4170 // This routine is used in conjunction with traverse(). //
4171 // //
4173 
4174 void tetgenmesh::memorypool::traversalinit()
4175 {
4176  uintptr_t alignptr;
4177 
4178  // Begin the traversal in the first block.
4179  pathblock = firstblock;
4180  // Find the first item in the block. Increment by the size of (void *).
4181  alignptr = (uintptr_t) (pathblock + 1);
4182  // Align with item on an `alignbytes'-byte boundary.
4183  pathitem = (void *)
4184  (alignptr + (uintptr_t) alignbytes -
4185  (alignptr % (uintptr_t) alignbytes));
4186  // Set the number of items left in the current block.
4187  pathitemsleft = itemsperblock;
4188 }
4189 
4191 // //
4192 // traverse() Find the next item in the list. //
4193 // //
4194 // This routine is used in conjunction with traversalinit(). Be forewarned //
4195 // that this routine successively returns all items in the list, including //
4196 // deallocated ones on the deaditemqueue. It's up to you to figure out which //
4197 // ones are actually dead. It can usually be done more space-efficiently by //
4198 // a routine that knows something about the structure of the item. //
4199 // //
4201 
4202 void* tetgenmesh::memorypool::traverse()
4203 {
4204  void *newitem;
4205  uintptr_t alignptr;
4206 
4207  // Stop upon exhausting the list of items.
4208  if (pathitem == nextitem) {
4209  return (void *) NULL;
4210  }
4211  // Check whether any untraversed items remain in the current block.
4212  if (pathitemsleft == 0) {
4213  // Find the next block.
4214  pathblock = (void **) *pathblock;
4215  // Find the first item in the block. Increment by the size of (void *).
4216  alignptr = (uintptr_t) (pathblock + 1);
4217  // Align with item on an `alignbytes'-byte boundary.
4218  pathitem = (void *)
4219  (alignptr + (uintptr_t) alignbytes -
4220  (alignptr % (uintptr_t) alignbytes));
4221  // Set the number of items left in the current block.
4222  pathitemsleft = itemsperblock;
4223  }
4224  newitem = pathitem;
4225  // Find the next item in the block.
4226  pathitem = (void *) ((uintptr_t) pathitem + itembytes);
4227  pathitemsleft--;
4228  return newitem;
4229 }
4230 
4232 // //
4233 // makeindex2pointmap() Create a map from index to vertices. //
4234 // //
4235 // 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
4236 // to each vertex is set into the array. The pointer to the first vertex is //
4237 // saved in 'idx2verlist[in->firstnumber]'. //
4238 // //
4240 
4241 void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
4242 {
4243  point pointloop;
4244  int idx;
4245 
4246  if (b->verbose > 1) {
4247  printf(" Constructing mapping from indices to points.\n");
4248  }
4249 
4250  idx2verlist = new point[points->items + 1];
4251 
4252  points->traversalinit();
4253  pointloop = pointtraverse();
4254  idx = in->firstnumber;
4255  while (pointloop != (point) NULL) {
4256  idx2verlist[idx++] = pointloop;
4257  pointloop = pointtraverse();
4258  }
4259 }
4260 
4262 // //
4263 // makesubfacemap() Create a map from vertex to subfaces incident at it. //
4264 // //
4265 // The map is returned in two arrays 'idx2faclist' and 'facperverlist'. All //
4266 // subfaces incident at i-th vertex (i is counted from 0) are found in the //
4267 // array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1]. //
4268 // Each entry in facperverlist[j] is a subface whose origin is the vertex. //
4269 // //
4270 // NOTE: These two arrays will be created inside this routine, don't forget //
4271 // to free them after using. //
4272 // //
4274 
4275 void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
4276  face*& facperverlist)
4277 {
4278  face shloop;
4279  int i, j, k;
4280 
4281  if (b->verbose > 1) {
4282  printf(" Making a map from points to subfaces.\n");
4283  }
4284 
4285  // Initialize 'idx2faclist'.
4286  idx2faclist = new int[points->items + 1];
4287  for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
4288 
4289  // Loop all subfaces, counter the number of subfaces incident at a vertex.
4290  pool->traversalinit();
4291  shloop.sh = shellfacetraverse(pool);
4292  while (shloop.sh != (shellface *) NULL) {
4293  // Increment the number of incident subfaces for each vertex.
4294  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4295  idx2faclist[j]++;
4296  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4297  idx2faclist[j]++;
4298  // Skip the third corner if it is a segment.
4299  if (shloop.sh[5] != NULL) {
4300  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4301  idx2faclist[j]++;
4302  }
4303  shloop.sh = shellfacetraverse(pool);
4304  }
4305 
4306  // Calculate the total length of array 'facperverlist'.
4307  j = idx2faclist[0];
4308  idx2faclist[0] = 0; // Array starts from 0 element.
4309  for (i = 0; i < points->items; i++) {
4310  k = idx2faclist[i + 1];
4311  idx2faclist[i + 1] = idx2faclist[i] + j;
4312  j = k;
4313  }
4314 
4315  // The total length is in the last unit of idx2faclist.
4316  facperverlist = new face[idx2faclist[i]];
4317 
4318  // Loop all subfaces again, remember the subfaces at each vertex.
4319  pool->traversalinit();
4320  shloop.sh = shellfacetraverse(pool);
4321  while (shloop.sh != (shellface *) NULL) {
4322  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4323  shloop.shver = 0; // save the origin.
4324  facperverlist[idx2faclist[j]] = shloop;
4325  idx2faclist[j]++;
4326  // Is it a subface or a subsegment?
4327  if (shloop.sh[5] != NULL) {
4328  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4329  shloop.shver = 2; // save the origin.
4330  facperverlist[idx2faclist[j]] = shloop;
4331  idx2faclist[j]++;
4332  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4333  shloop.shver = 4; // save the origin.
4334  facperverlist[idx2faclist[j]] = shloop;
4335  idx2faclist[j]++;
4336  } else {
4337  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4338  shloop.shver = 1; // save the origin.
4339  facperverlist[idx2faclist[j]] = shloop;
4340  idx2faclist[j]++;
4341  }
4342  shloop.sh = shellfacetraverse(pool);
4343  }
4344 
4345  // Contents in 'idx2faclist' are shifted, now shift them back.
4346  for (i = points->items - 1; i >= 0; i--) {
4347  idx2faclist[i + 1] = idx2faclist[i];
4348  }
4349  idx2faclist[0] = 0;
4350 }
4351 
4353 // //
4354 // tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
4355 // //
4357 
4358 void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
4359 {
4360  // Set tetrahedron's vertices to NULL. This makes it possible to detect
4361  // dead tetrahedra when traversing the list of all tetrahedra.
4362  dyingtetrahedron[4] = (tetrahedron) NULL;
4363 
4364  // Dealloc the space to subfaces/subsegments.
4365  if (dyingtetrahedron[8] != NULL) {
4366  tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
4367  }
4368  if (dyingtetrahedron[9] != NULL) {
4369  tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
4370  }
4371 
4372  tetrahedrons->dealloc((void *) dyingtetrahedron);
4373 }
4374 
4376 // //
4377 // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
4378 // //
4380 
4381 tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
4382 {
4383  tetrahedron *newtetrahedron;
4384 
4385  do {
4386  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4387  if (newtetrahedron == (tetrahedron *) NULL) {
4388  return (tetrahedron *) NULL;
4389  }
4390  } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
4391  ((point) newtetrahedron[7] == dummypoint));
4392  return newtetrahedron;
4393 }
4394 
4395 tetgenmesh::tetrahedron* tetgenmesh::alltetrahedrontraverse()
4396 {
4397  tetrahedron *newtetrahedron;
4398 
4399  do {
4400  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4401  if (newtetrahedron == (tetrahedron *) NULL) {
4402  return (tetrahedron *) NULL;
4403  }
4404  } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
4405  return newtetrahedron;
4406 }
4407 
4409 // //
4410 // shellfacedealloc() Deallocate space for a shellface, marking it dead. //
4411 // Used both for dealloc a subface and subsegment. //
4412 // //
4414 
4415 void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
4416 {
4417  // Set shellface's vertices to NULL. This makes it possible to detect dead
4418  // shellfaces when traversing the list of all shellfaces.
4419  dyingsh[3] = (shellface) NULL;
4420  pool->dealloc((void *) dyingsh);
4421 }
4422 
4424 // //
4425 // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
4426 // for both subfaces and subsegments pool traverse. //
4427 // //
4429 
4430 tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
4431 {
4432  shellface *newshellface;
4433 
4434  do {
4435  newshellface = (shellface *) pool->traverse();
4436  if (newshellface == (shellface *) NULL) {
4437  return (shellface *) NULL;
4438  }
4439  } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
4440  return newshellface;
4441 }
4442 
4443 
4445 // //
4446 // pointdealloc() Deallocate space for a point, marking it dead. //
4447 // //
4449 
4450 void tetgenmesh::pointdealloc(point dyingpoint)
4451 {
4452  // Mark the point as dead. This makes it possible to detect dead points
4453  // when traversing the list of all points.
4454  setpointtype(dyingpoint, DEADVERTEX);
4455  points->dealloc((void *) dyingpoint);
4456 }
4457 
4459 // //
4460 // pointtraverse() Traverse the points, skipping dead ones. //
4461 // //
4463 
4464 tetgenmesh::point tetgenmesh::pointtraverse()
4465 {
4466  point newpoint;
4467 
4468  do {
4469  newpoint = (point) points->traverse();
4470  if (newpoint == (point) NULL) {
4471  return (point) NULL;
4472  }
4473  } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
4474  return newpoint;
4475 }
4476 
4478 // //
4479 // maketetrahedron() Create a new tetrahedron. //
4480 // //
4482 
4483 void tetgenmesh::maketetrahedron(triface *newtet)
4484 {
4485  newtet->tet = (tetrahedron *) tetrahedrons->alloc();
4486 
4487  // Initialize the four adjoining tetrahedra to be "outer space".
4488  newtet->tet[0] = NULL;
4489  newtet->tet[1] = NULL;
4490  newtet->tet[2] = NULL;
4491  newtet->tet[3] = NULL;
4492  // Four NULL vertices.
4493  newtet->tet[4] = NULL;
4494  newtet->tet[5] = NULL;
4495  newtet->tet[6] = NULL;
4496  newtet->tet[7] = NULL;
4497  // No attached segments and subfaces yet.
4498  newtet->tet[8] = NULL;
4499  newtet->tet[9] = NULL;
4500  // Initialize the marker (clear all flags).
4501  setelemmarker(newtet->tet, 0);
4502  for (int i = 0; i < numelemattrib; i++) {
4503  setelemattribute(newtet->tet, i, 0.0);
4504  }
4505  if (b->varvolume) {
4506  setvolumebound(newtet->tet, -1.0);
4507  }
4508 
4509  // Initialize the version to be Zero.
4510  newtet->ver = 11;
4511 }
4512 
4514 // //
4515 // makeshellface() Create a new shellface with version zero. Used for //
4516 // both subfaces and subsegments. //
4517 // //
4519 
4520 void tetgenmesh::makeshellface(memorypool *pool, face *newface)
4521 {
4522  newface->sh = (shellface *) pool->alloc();
4523 
4524  // No adjointing subfaces.
4525  newface->sh[0] = NULL;
4526  newface->sh[1] = NULL;
4527  newface->sh[2] = NULL;
4528  // Three NULL vertices.
4529  newface->sh[3] = NULL;
4530  newface->sh[4] = NULL;
4531  newface->sh[5] = NULL;
4532  // No adjoining subsegments.
4533  newface->sh[6] = NULL;
4534  newface->sh[7] = NULL;
4535  newface->sh[8] = NULL;
4536  // No adjoining tetrahedra.
4537  newface->sh[9] = NULL;
4538  newface->sh[10] = NULL;
4539  if (checkconstraints) {
4540  // Initialize the maximum area bound.
4541  setareabound(*newface, 0.0);
4542  }
4543  // Set the boundary marker to zero.
4544  setshellmark(*newface, 0);
4545  // Clear the infection and marktest bits.
4546  ((int *) (newface->sh))[shmarkindex + 1] = 0;
4547  if (useinsertradius) {
4548  setfacetindex(*newface, 0);
4549  }
4550 
4551  newface->shver = 0;
4552 }
4553 
4555 // //
4556 // makepoint() Create a new point. //
4557 // //
4559 
4560 void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
4561 {
4562  int i;
4563 
4564  *pnewpoint = (point) points->alloc();
4565 
4566  // Initialize the point attributes.
4567  for (i = 0; i < numpointattrib; i++) {
4568  (*pnewpoint)[3 + i] = 0.0;
4569  }
4570  // Initialize the metric tensor.
4571  for (i = 0; i < sizeoftensor; i++) {
4572  (*pnewpoint)[pointmtrindex + i] = 0.0;
4573  }
4574  setpoint2tet(*pnewpoint, NULL);
4575  setpoint2ppt(*pnewpoint, NULL);
4576  if (b->plc || b->refine) {
4577  // Initialize the point-to-simplex field.
4578  setpoint2sh(*pnewpoint, NULL);
4579  if (b->metric && (bgm != NULL)) {
4580  setpoint2bgmtet(*pnewpoint, NULL);
4581  }
4582  }
4583  // Initialize the point marker (starting from in->firstnumber).
4584  setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
4585  // Clear all flags.
4586  ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
4587  // Initialize (set) the point type.
4588  setpointtype(*pnewpoint, vtype);
4589 }
4590 
4592 // //
4593 // initializepools() Calculate the sizes of the point, tetrahedron, and //
4594 // subface. Initialize their memory pools. //
4595 // //
4596 // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
4597 // 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'. They are //
4598 // used to find values within each point and tetrahedron, respectively. //
4599 // //
4601 
4602 void tetgenmesh::initializepools()
4603 {
4604  int pointsize = 0, elesize = 0, shsize = 0;
4605  int i;
4606 
4607  if (b->verbose) {
4608  printf(" Initializing memorypools.\n");
4609  printf(" tetrahedron per block: %d.\n", b->tetrahedraperblock);
4610  }
4611 
4612  inittables();
4613 
4614  // There are three input point lists available, which are in, addin,
4615  // and bgm->in. These point lists may have different number of
4616  // attributes. Decide the maximum number.
4617  numpointattrib = in->numberofpointattributes;
4618  if (bgm != NULL) {
4619  if (bgm->in->numberofpointattributes > numpointattrib) {
4620  numpointattrib = bgm->in->numberofpointattributes;
4621  }
4622  }
4623  if (addin != NULL) {
4624  if (addin->numberofpointattributes > numpointattrib) {
4625  numpointattrib = addin->numberofpointattributes;
4626  }
4627  }
4628  if (b->weighted || b->flipinsert) { // -w or -L.
4629  // The internal number of point attribute needs to be at least 1
4630  // (for storing point weights).
4631  if (numpointattrib == 0) {
4632  numpointattrib = 1;
4633  }
4634  }
4635 
4636  // Default varconstraint = 0;
4637  if (in->segmentconstraintlist || in->facetconstraintlist) {
4638  checkconstraints = 1;
4639  }
4640  if (b->plc || b->refine) {
4641  // Save the insertion radius for Steiner points if boundaries
4642  // are allowed be split.
4643  if (!b->nobisect || checkconstraints) {
4644  useinsertradius = 1;
4645  }
4646  }
4647 
4648  // The index within each point at which its metric tensor is found.
4649  // Each vertex has three coordinates.
4650  if (b->psc) {
4651  // '-s' option (PSC), the u,v coordinates are provided.
4652  pointmtrindex = 5 + numpointattrib;
4653  // The index within each point at which its u, v coordinates are found.
4654  // Comment: They are saved after the list of point attributes.
4655  pointparamindex = pointmtrindex - 2;
4656  } else {
4657  pointmtrindex = 3 + numpointattrib;
4658  }
4659  // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
4660  if (b->metric) {
4661  // Decide the size (1, 3, or 6) of the metric tensor.
4662  if (bgm != (tetgenmesh *) NULL) {
4663  // A background mesh is allocated. It may not exist though.
4664  sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
4665  bgm->in->numberofpointmtrs : in->numberofpointmtrs;
4666  } else {
4667  // No given background mesh - Itself is a background mesh.
4668  sizeoftensor = in->numberofpointmtrs;
4669  }
4670  // Make sure sizeoftensor is at least 1.
4671  sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
4672  } else {
4673  // For '-q' option. Make sure to have space for saving a scalar value.
4674  sizeoftensor = b->quality ? 1 : 0;
4675  }
4676  if (useinsertradius) {
4677  // Increase a space (REAL) for saving point insertion radius, it is
4678  // saved directly after the metric.
4679  sizeoftensor++;
4680  }
4681  pointinsradiusindex = pointmtrindex + sizeoftensor - 1;
4682  // The index within each point at which an element pointer is found, where
4683  // the index is measured in pointers. Ensure the index is aligned to a
4684  // sizeof(tetrahedron)-byte address.
4685  point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
4686  + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
4687  if (b->plc || b->refine || b->voroout) {
4688  // Increase the point size by three pointers, which are:
4689  // - a pointer to a tet, read by point2tet();
4690  // - a pointer to a parent point, read by point2ppt()).
4691  // - a pointer to a subface or segment, read by point2sh();
4692  if (b->metric && (bgm != (tetgenmesh *) NULL)) {
4693  // Increase one pointer into the background mesh, point2bgmtet().
4694  pointsize = (point2simindex + 4) * sizeof(tetrahedron);
4695  } else {
4696  pointsize = (point2simindex + 3) * sizeof(tetrahedron);
4697  }
4698  } else {
4699  // Increase the point size by two pointer, which are:
4700  // - a pointer to a tet, read by point2tet();
4701  // - a pointer to a parent point, read by point2ppt()). -- Used by btree.
4702  pointsize = (point2simindex + 2) * sizeof(tetrahedron);
4703  }
4704  // The index within each point at which the boundary marker is found,
4705  // Ensure the point marker is aligned to a sizeof(int)-byte address.
4706  pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
4707  // Now point size is the ints (indicated by pointmarkindex) plus:
4708  // - an integer for boundary marker;
4709  // - an integer for vertex type;
4710  // - an integer for geometry tag (optional, -s option).
4711  pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
4712 
4713  // Initialize the pool of vertices.
4714  points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
4715 
4716  if (b->verbose) {
4717  printf(" Size of a point: %d bytes.\n", points->itembytes);
4718  }
4719 
4720  // Initialize the infinite vertex.
4721  dummypoint = (point) new char[pointsize];
4722  // Initialize all fields of this point.
4723  dummypoint[0] = 0.0;
4724  dummypoint[1] = 0.0;
4725  dummypoint[2] = 0.0;
4726  for (i = 0; i < numpointattrib; i++) {
4727  dummypoint[3 + i] = 0.0;
4728  }
4729  // Initialize the metric tensor.
4730  for (i = 0; i < sizeoftensor; i++) {
4731  dummypoint[pointmtrindex + i] = 0.0;
4732  }
4733  setpoint2tet(dummypoint, NULL);
4734  setpoint2ppt(dummypoint, NULL);
4735  if (b->plc || b->psc || b->refine) {
4736  // Initialize the point-to-simplex field.
4737  setpoint2sh(dummypoint, NULL);
4738  if (b->metric && (bgm != NULL)) {
4739  setpoint2bgmtet(dummypoint, NULL);
4740  }
4741  }
4742  // Initialize the point marker (starting from in->firstnumber).
4743  setpointmark(dummypoint, -1); // The unique marker for dummypoint.
4744  // Clear all flags.
4745  ((int *) (dummypoint))[pointmarkindex + 1] = 0;
4746  // Initialize (set) the point type.
4747  setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
4748 
4749  // The number of bytes occupied by a tetrahedron is varying by the user-
4750  // specified options. The contents of the first 12 pointers are listed
4751  // in the following table:
4752  // [0] |__ neighbor at f0 __|
4753  // [1] |__ neighbor at f1 __|
4754  // [2] |__ neighbor at f2 __|
4755  // [3] |__ neighbor at f3 __|
4756  // [4] |_____ vertex p0 ____|
4757  // [5] |_____ vertex p1 ____|
4758  // [6] |_____ vertex p2 ____|
4759  // [7] |_____ vertex p3 ____|
4760  // [8] |__ segments array __| (used by -p)
4761  // [9] |__ subfaces array __| (used by -p)
4762  // [10] |_____ reserved _____|
4763  // [11] |___ elem marker ____| (used as an integer)
4764 
4765  elesize = 12 * sizeof(tetrahedron);
4766 
4767  // The index to find the element markers. An integer containing varies
4768  // flags and element counter.
4769  if (!(sizeof(int) <= sizeof(tetrahedron)) ||
4770  ((sizeof(tetrahedron) % sizeof(int)))) {
4771  terminatetetgen(this, 2);
4772  }
4773  elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
4774 
4775  // The actual number of element attributes. Note that if the
4776  // `b->regionattrib' flag is set, an additional attribute will be added.
4777  numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
4778 
4779  // The index within each element at which its attributes are found, where
4780  // the index is measured in REALs.
4781  elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
4782  // The index within each element at which the maximum volume bound is
4783  // found, where the index is measured in REALs.
4784  volumeboundindex = elemattribindex + numelemattrib;
4785  // If element attributes or an constraint are needed, increase the number
4786  // of bytes occupied by an element.
4787  if (b->varvolume) {
4788  elesize = (volumeboundindex + 1) * sizeof(REAL);
4789  } else if (numelemattrib > 0) {
4790  elesize = volumeboundindex * sizeof(REAL);
4791  }
4792 
4793 
4794  // Having determined the memory size of an element, initialize the pool.
4795  tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
4796  16);
4797 
4798  if (b->verbose) {
4799  printf(" Size of a tetrahedron: %d (%d) bytes.\n", elesize,
4800  tetrahedrons->itembytes);
4801  }
4802 
4803  if (b->plc || b->refine) { // if (b->useshelles) {
4804  // The number of bytes occupied by a subface. The list of pointers
4805  // stored in a subface are: three to other subfaces, three to corners,
4806  // three to subsegments, two to tetrahedra.
4807  shsize = 11 * sizeof(shellface);
4808  // The index within each subface at which the maximum area bound is
4809  // found, where the index is measured in REALs.
4810  areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
4811  // If -q switch is in use, increase the number of bytes occupied by
4812  // a subface for saving maximum area bound.
4813  if (checkconstraints) {
4814  shsize = (areaboundindex + 1) * sizeof(REAL);
4815  } else {
4816  shsize = areaboundindex * sizeof(REAL);
4817  }
4818  // The index within subface at which the facet marker is found. Ensure
4819  // the marker is aligned to a sizeof(int)-byte address.
4820  shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
4821  // Increase the number of bytes by two or three integers, one for facet
4822  // marker, one for shellface type and flags, and optionally one
4823  // for storing facet index (for mesh refinement).
4824  shsize = (shmarkindex + 2 + useinsertradius) * sizeof(shellface);
4825 
4826  // Initialize the pool of subfaces. Each subface record is eight-byte
4827  // aligned so it has room to store an edge version (from 0 to 5) in
4828  // the least three bits.
4829  subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4830 
4831  if (b->verbose) {
4832  printf(" Size of a shellface: %d (%d) bytes.\n", shsize,
4833  subfaces->itembytes);
4834  }
4835 
4836  // Initialize the pool of subsegments. The subsegment's record is same
4837  // with subface.
4838  subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4839 
4840  // Initialize the pool for tet-subseg connections.
4841  tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock,
4842  sizeof(void *), 0);
4843  // Initialize the pool for tet-subface connections.
4844  tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock,
4845  sizeof(void *), 0);
4846 
4847  // Initialize arraypools for segment & facet recovery.
4848  subsegstack = new arraypool(sizeof(face), 10);
4849  subfacstack = new arraypool(sizeof(face), 10);
4850  subvertstack = new arraypool(sizeof(point), 8);
4851 
4852  // Initialize arraypools for surface point insertion/deletion.
4853  caveshlist = new arraypool(sizeof(face), 8);
4854  caveshbdlist = new arraypool(sizeof(face), 8);
4855  cavesegshlist = new arraypool(sizeof(face), 4);
4856 
4857  cavetetshlist = new arraypool(sizeof(face), 8);
4858  cavetetseglist = new arraypool(sizeof(face), 8);
4859  caveencshlist = new arraypool(sizeof(face), 8);
4860  caveencseglist = new arraypool(sizeof(face), 8);
4861  }
4862 
4863  // Initialize the pools for flips.
4864  flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
4865  unflipqueue = new arraypool(sizeof(badface), 10);
4866 
4867  // Initialize the arraypools for point insertion.
4868  cavetetlist = new arraypool(sizeof(triface), 10);
4869  cavebdrylist = new arraypool(sizeof(triface), 10);
4870  caveoldtetlist = new arraypool(sizeof(triface), 10);
4871  cavetetvertlist = new arraypool(sizeof(point), 10);
4872 }
4873 
4877 
4881 
4882 // PI is the ratio of a circle's circumference to its diameter.
4883 REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
4884 
4886 // //
4887 // insphere_s() Insphere test with symbolic perturbation. //
4888 // //
4889 // Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
4890 // outside the circumscribed sphere of the four points. //
4891 // //
4892 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4893 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4894 // points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4895 // //
4896 // Return a positive value (> 0) if pe lies inside, a negative value (< 0) //
4897 // if pe lies outside the sphere, the returned value will not be zero. //
4898 // //
4900 
4901 REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
4902 {
4903  REAL sign;
4904 
4905  sign = insphere(pa, pb, pc, pd, pe);
4906  if (sign != 0.0) {
4907  return sign;
4908  }
4909 
4910  // Symbolic perturbation.
4911  point pt[5], swappt;
4912  REAL oriA, oriB;
4913  int swaps, count;
4914  int n, i;
4915 
4916  pt[0] = pa;
4917  pt[1] = pb;
4918  pt[2] = pc;
4919  pt[3] = pd;
4920  pt[4] = pe;
4921 
4922  // Sort the five points such that their indices are in the increasing
4923  // order. An optimized bubble sort algorithm is used, i.e., it has
4924  // the worst case O(n^2) runtime, but it is usually much faster.
4925  swaps = 0; // Record the total number of swaps.
4926  n = 5;
4927  do {
4928  count = 0;
4929  n = n - 1;
4930  for (i = 0; i < n; i++) {
4931  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
4932  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
4933  count++;
4934  }
4935  }
4936  swaps += count;
4937  } while (count > 0); // Continue if some points are swapped.
4938 
4939  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
4940  if (oriA != 0.0) {
4941  // Flip the sign if there are odd number of swaps.
4942  if ((swaps % 2) != 0) oriA = -oriA;
4943  return oriA;
4944  }
4945 
4946  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
4947  if (oriB == 0.0) {
4948  terminatetetgen(this, 2);
4949  }
4950  // Flip the sign if there are odd number of swaps.
4951  if ((swaps % 2) != 0) oriB = -oriB;
4952  return oriB;
4953 }
4954 
4956 // //
4957 // orient4d_s() 4d orientation test with symbolic perturbation. //
4958 // //
4959 // Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
4960 // point pe' in R^4 lies below or above the hyperplane passing through the //
4961 // four points pa', pb', pc', and pd'. //
4962 // //
4963 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4964 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4965 // the points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4966 // //
4967 // Return a positive value (> 0) if pe' lies below, a negative value (< 0) //
4968 // if pe' lies above the hyperplane, the returned value should not be zero. //
4969 // //
4971 
4972 REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
4973  REAL aheight, REAL bheight, REAL cheight,
4974  REAL dheight, REAL eheight)
4975 {
4976  REAL sign;
4977 
4978  sign = orient4d(pa, pb, pc, pd, pe,
4979  aheight, bheight, cheight, dheight, eheight);
4980  if (sign != 0.0) {
4981  return sign;
4982  }
4983 
4984  // Symbolic perturbation.
4985  point pt[5], swappt;
4986  REAL oriA, oriB;
4987  int swaps, count;
4988  int n, i;
4989 
4990  pt[0] = pa;
4991  pt[1] = pb;
4992  pt[2] = pc;
4993  pt[3] = pd;
4994  pt[4] = pe;
4995 
4996  // Sort the five points such that their indices are in the increasing
4997  // order. An optimized bubble sort algorithm is used, i.e., it has
4998  // the worst case O(n^2) runtime, but it is usually much faster.
4999  swaps = 0; // Record the total number of swaps.
5000  n = 5;
5001  do {
5002  count = 0;
5003  n = n - 1;
5004  for (i = 0; i < n; i++) {
5005  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
5006  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
5007  count++;
5008  }
5009  }
5010  swaps += count;
5011  } while (count > 0); // Continue if some points are swapped.
5012 
5013  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
5014  if (oriA != 0.0) {
5015  // Flip the sign if there are odd number of swaps.
5016  if ((swaps % 2) != 0) oriA = -oriA;
5017  return oriA;
5018  }
5019 
5020  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
5021  if (oriB == 0.0) {
5022  terminatetetgen(this, 2);
5023  }
5024  // Flip the sign if there are odd number of swaps.
5025  if ((swaps % 2) != 0) oriB = -oriB;
5026  return oriB;
5027 }
5028 
5030 // //
5031 // tri_edge_test() Triangle-edge intersection test. //
5032 // //
5033 // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
5034 // Q) in 3D, and tests if they intersect each other. //
5035 // //
5036 // If the point 'R' is not NULL, it lies strictly above the plane defined by //
5037 // A, B, C. It is used in test when T and E are coplanar. //
5038 // //
5039 // If T and E intersect each other, they may intersect in different ways. If //
5040 // 'level' > 0, their intersection type will be reported 'types' and 'pos'. //
5041 // //
5042 // The return value indicates one of the following cases: //
5043 // - 0, T and E are disjoint. //
5044 // - 1, T and E intersect each other. //
5045 // - 2, T and E are not coplanar. They intersect at a single point. //
5046 // - 4, T and E are coplanar. They intersect at a single point or a line //
5047 // segment (if types[1] != DISJOINT). //
5048 // //
5050 
5051 #define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
5052 
5053 #define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
5054 
5055 int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q,
5056  point R, int level, int *types, int *pos)
5057 {
5058  point U[3], V[3]; // The permuted vectors of points.
5059  int pu[3], pv[3]; // The original positions of points.
5060  REAL abovept[3];
5061  REAL sA, sB, sC;
5062  REAL s1, s2, s3, s4;
5063  int z1;
5064 
5065  if (R == NULL) {
5066  // Calculate a lift point.
5067  if (1) {
5068  REAL n[3], len;
5069  // Calculate a lift point, saved in dummypoint.
5070  facenormal(A, B, C, n, 1, NULL);
5071  len = sqrt(dot(n, n));
5072  if (len != 0) {
5073  n[0] /= len;
5074  n[1] /= len;
5075  n[2] /= len;
5076  len = distance(A, B);
5077  len += distance(B, C);
5078  len += distance(C, A);
5079  len /= 3.0;
5080  R = abovept; //dummypoint;
5081  R[0] = A[0] + len * n[0];
5082  R[1] = A[1] + len * n[1];
5083  R[2] = A[2] + len * n[2];
5084  } else {
5085  // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
5086  // to a line. We need a line-line intersection test.
5087  // !!! A non-save return value.!!!
5088  return 0; // DISJOINT
5089  }
5090  }
5091  }
5092 
5093  // Test A's, B's, and C's orientations wrt plane PQR.
5094  sA = orient3d(P, Q, R, A);
5095  sB = orient3d(P, Q, R, B);
5096  sC = orient3d(P, Q, R, C);
5097 
5098 
5099  if (sA < 0) {
5100  if (sB < 0) {
5101  if (sC < 0) { // (---).
5102  return 0;
5103  } else {
5104  if (sC > 0) { // (--+).
5105  // All points are in the right positions.
5106  SETVECTOR3(U, A, B, C); // I3
5107  SETVECTOR3(V, P, Q, R); // I2
5108  SETVECTOR3(pu, 0, 1, 2);
5109  SETVECTOR3(pv, 0, 1, 2);
5110  z1 = 0;
5111  } else { // (--0).
5112  SETVECTOR3(U, A, B, C); // I3
5113  SETVECTOR3(V, P, Q, R); // I2
5114  SETVECTOR3(pu, 0, 1, 2);
5115  SETVECTOR3(pv, 0, 1, 2);
5116  z1 = 1;
5117  }
5118  }
5119  } else {
5120  if (sB > 0) {
5121  if (sC < 0) { // (-+-).
5122  SETVECTOR3(U, C, A, B); // PT = ST
5123  SETVECTOR3(V, P, Q, R); // I2
5124  SETVECTOR3(pu, 2, 0, 1);
5125  SETVECTOR3(pv, 0, 1, 2);
5126  z1 = 0;
5127  } else {
5128  if (sC > 0) { // (-++).
5129  SETVECTOR3(U, B, C, A); // PT = ST x ST
5130  SETVECTOR3(V, Q, P, R); // PL = SL
5131  SETVECTOR3(pu, 1, 2, 0);
5132  SETVECTOR3(pv, 1, 0, 2);
5133  z1 = 0;
5134  } else { // (-+0).
5135  SETVECTOR3(U, C, A, B); // PT = ST
5136  SETVECTOR3(V, P, Q, R); // I2
5137  SETVECTOR3(pu, 2, 0, 1);
5138  SETVECTOR3(pv, 0, 1, 2);
5139  z1 = 2;
5140  }
5141  }
5142  } else {
5143  if (sC < 0) { // (-0-).
5144  SETVECTOR3(U, C, A, B); // PT = ST
5145  SETVECTOR3(V, P, Q, R); // I2
5146  SETVECTOR3(pu, 2, 0, 1);
5147  SETVECTOR3(pv, 0, 1, 2);
5148  z1 = 1;
5149  } else {
5150  if (sC > 0) { // (-0+).
5151  SETVECTOR3(U, B, C, A); // PT = ST x ST
5152  SETVECTOR3(V, Q, P, R); // PL = SL
5153  SETVECTOR3(pu, 1, 2, 0);
5154  SETVECTOR3(pv, 1, 0, 2);
5155  z1 = 2;
5156  } else { // (-00).
5157  SETVECTOR3(U, B, C, A); // PT = ST x ST
5158  SETVECTOR3(V, Q, P, R); // PL = SL
5159  SETVECTOR3(pu, 1, 2, 0);
5160  SETVECTOR3(pv, 1, 0, 2);
5161  z1 = 3;
5162  }
5163  }
5164  }
5165  }
5166  } else {
5167  if (sA > 0) {
5168  if (sB < 0) {
5169  if (sC < 0) { // (+--).
5170  SETVECTOR3(U, B, C, A); // PT = ST x ST
5171  SETVECTOR3(V, P, Q, R); // I2
5172  SETVECTOR3(pu, 1, 2, 0);
5173  SETVECTOR3(pv, 0, 1, 2);
5174  z1 = 0;
5175  } else {
5176  if (sC > 0) { // (+-+).
5177  SETVECTOR3(U, C, A, B); // PT = ST
5178  SETVECTOR3(V, Q, P, R); // PL = SL
5179  SETVECTOR3(pu, 2, 0, 1);
5180  SETVECTOR3(pv, 1, 0, 2);
5181  z1 = 0;
5182  } else { // (+-0).
5183  SETVECTOR3(U, C, A, B); // PT = ST
5184  SETVECTOR3(V, Q, P, R); // PL = SL
5185  SETVECTOR3(pu, 2, 0, 1);
5186  SETVECTOR3(pv, 1, 0, 2);
5187  z1 = 2;
5188  }
5189  }
5190  } else {
5191  if (sB > 0) {
5192  if (sC < 0) { // (++-).
5193  SETVECTOR3(U, A, B, C); // I3
5194  SETVECTOR3(V, Q, P, R); // PL = SL
5195  SETVECTOR3(pu, 0, 1, 2);
5196  SETVECTOR3(pv, 1, 0, 2);
5197  z1 = 0;
5198  } else {
5199  if (sC > 0) { // (+++).
5200  return 0;
5201  } else { // (++0).
5202  SETVECTOR3(U, A, B, C); // I3
5203  SETVECTOR3(V, Q, P, R); // PL = SL
5204  SETVECTOR3(pu, 0, 1, 2);
5205  SETVECTOR3(pv, 1, 0, 2);
5206  z1 = 1;
5207  }
5208  }
5209  } else { // (+0#)
5210  if (sC < 0) { // (+0-).
5211  SETVECTOR3(U, B, C, A); // PT = ST x ST
5212  SETVECTOR3(V, P, Q, R); // I2
5213  SETVECTOR3(pu, 1, 2, 0);
5214  SETVECTOR3(pv, 0, 1, 2);
5215  z1 = 2;
5216  } else {
5217  if (sC > 0) { // (+0+).
5218  SETVECTOR3(U, C, A, B); // PT = ST
5219  SETVECTOR3(V, Q, P, R); // PL = SL
5220  SETVECTOR3(pu, 2, 0, 1);
5221  SETVECTOR3(pv, 1, 0, 2);
5222  z1 = 1;
5223  } else { // (+00).
5224  SETVECTOR3(U, B, C, A); // PT = ST x ST
5225  SETVECTOR3(V, P, Q, R); // I2
5226  SETVECTOR3(pu, 1, 2, 0);
5227  SETVECTOR3(pv, 0, 1, 2);
5228  z1 = 3;
5229  }
5230  }
5231  }
5232  }
5233  } else {
5234  if (sB < 0) {
5235  if (sC < 0) { // (0--).
5236  SETVECTOR3(U, B, C, A); // PT = ST x ST
5237  SETVECTOR3(V, P, Q, R); // I2
5238  SETVECTOR3(pu, 1, 2, 0);
5239  SETVECTOR3(pv, 0, 1, 2);
5240  z1 = 1;
5241  } else {
5242  if (sC > 0) { // (0-+).
5243  SETVECTOR3(U, A, B, C); // I3
5244  SETVECTOR3(V, P, Q, R); // I2
5245  SETVECTOR3(pu, 0, 1, 2);
5246  SETVECTOR3(pv, 0, 1, 2);
5247  z1 = 2;
5248  } else { // (0-0).
5249  SETVECTOR3(U, C, A, B); // PT = ST
5250  SETVECTOR3(V, Q, P, R); // PL = SL
5251  SETVECTOR3(pu, 2, 0, 1);
5252  SETVECTOR3(pv, 1, 0, 2);
5253  z1 = 3;
5254  }
5255  }
5256  } else {
5257  if (sB > 0) {
5258  if (sC < 0) { // (0+-).
5259  SETVECTOR3(U, A, B, C); // I3
5260  SETVECTOR3(V, Q, P, R); // PL = SL
5261  SETVECTOR3(pu, 0, 1, 2);
5262  SETVECTOR3(pv, 1, 0, 2);
5263  z1 = 2;
5264  } else {
5265  if (sC > 0) { // (0++).
5266  SETVECTOR3(U, B, C, A); // PT = ST x ST
5267  SETVECTOR3(V, Q, P, R); // PL = SL
5268  SETVECTOR3(pu, 1, 2, 0);
5269  SETVECTOR3(pv, 1, 0, 2);
5270  z1 = 1;
5271  } else { // (0+0).
5272  SETVECTOR3(U, C, A, B); // PT = ST
5273  SETVECTOR3(V, P, Q, R); // I2
5274  SETVECTOR3(pu, 2, 0, 1);
5275  SETVECTOR3(pv, 0, 1, 2);
5276  z1 = 3;
5277  }
5278  }
5279  } else { // (00#)
5280  if (sC < 0) { // (00-).
5281  SETVECTOR3(U, A, B, C); // I3
5282  SETVECTOR3(V, Q, P, R); // PL = SL
5283  SETVECTOR3(pu, 0, 1, 2);
5284  SETVECTOR3(pv, 1, 0, 2);
5285  z1 = 3;
5286  } else {
5287  if (sC > 0) { // (00+).
5288  SETVECTOR3(U, A, B, C); // I3
5289  SETVECTOR3(V, P, Q, R); // I2
5290  SETVECTOR3(pu, 0, 1, 2);
5291  SETVECTOR3(pv, 0, 1, 2);
5292  z1 = 3;
5293  } else { // (000)
5294  // Not possible unless ABC is degenerate.
5295  // Avoiding compiler warnings.
5296  SETVECTOR3(U, A, B, C); // I3
5297  SETVECTOR3(V, P, Q, R); // I2
5298  SETVECTOR3(pu, 0, 1, 2);
5299  SETVECTOR3(pv, 0, 1, 2);
5300  z1 = 4;
5301  }
5302  }
5303  }
5304  }
5305  }
5306  }
5307 
5308  s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q
5309  s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P
5310 
5311  if (s1 > 0) {
5312  return 0;
5313  }
5314  if (s2 < 0) {
5315  return 0;
5316  }
5317 
5318  if (level == 0) {
5319  return 1; // They are intersected.
5320  }
5321 
5322 
5323  if (z1 == 1) {
5324  if (s1 == 0) { // (0###)
5325  // C = Q.
5326  types[0] = (int) SHAREVERT;
5327  pos[0] = pu[2]; // C
5328  pos[1] = pv[1]; // Q
5329  types[1] = (int) DISJOINT;
5330  } else {
5331  if (s2 == 0) { // (#0##)
5332  // C = P.
5333  types[0] = (int) SHAREVERT;
5334  pos[0] = pu[2]; // C
5335  pos[1] = pv[0]; // P
5336  types[1] = (int) DISJOINT;
5337  } else { // (-+##)
5338  // C in [P, Q].
5339  types[0] = (int) ACROSSVERT;
5340  pos[0] = pu[2]; // C
5341  pos[1] = pv[0]; // [P, Q]
5342  types[1] = (int) DISJOINT;
5343  }
5344  }
5345  return 4;
5346  }
5347 
5348  s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P
5349  s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q
5350 
5351  if (z1 == 0) { // (tritri-03)
5352  if (s1 < 0) {
5353  if (s3 > 0) {
5354  if (s4 > 0) {
5355  // [P, Q] overlaps [k, l] (-+++).
5356  types[0] = (int) ACROSSEDGE;
5357  pos[0] = pu[2]; // [C, A]
5358  pos[1] = pv[0]; // [P, Q]
5359  types[1] = (int) TOUCHFACE;
5360  pos[2] = 3; // [A, B, C]
5361  pos[3] = pv[1]; // Q
5362  } else {
5363  if (s4 == 0) {
5364  // Q = l, [P, Q] contains [k, l] (-++0).
5365  types[0] = (int) ACROSSEDGE;
5366  pos[0] = pu[2]; // [C, A]
5367  pos[1] = pv[0]; // [P, Q]
5368  types[1] = (int) TOUCHEDGE;
5369  pos[2] = pu[1]; // [B, C]
5370  pos[3] = pv[1]; // Q
5371  } else { // s4 < 0
5372  // [P, Q] contains [k, l] (-++-).
5373  types[0] = (int) ACROSSEDGE;
5374  pos[0] = pu[2]; // [C, A]
5375  pos[1] = pv[0]; // [P, Q]
5376  types[1] = (int) ACROSSEDGE;
5377  pos[2] = pu[1]; // [B, C]
5378  pos[3] = pv[0]; // [P, Q]
5379  }
5380  }
5381  } else {
5382  if (s3 == 0) {
5383  if (s4 > 0) {
5384  // P = k, [P, Q] in [k, l] (-+0+).
5385  types[0] = (int) TOUCHEDGE;
5386  pos[0] = pu[2]; // [C, A]
5387  pos[1] = pv[0]; // P
5388  types[1] = (int) TOUCHFACE;
5389  pos[2] = 3; // [A, B, C]
5390  pos[3] = pv[1]; // Q
5391  } else {
5392  if (s4 == 0) {
5393  // [P, Q] = [k, l] (-+00).
5394  types[0] = (int) TOUCHEDGE;
5395  pos[0] = pu[2]; // [C, A]
5396  pos[1] = pv[0]; // P
5397  types[1] = (int) TOUCHEDGE;
5398  pos[2] = pu[1]; // [B, C]
5399  pos[3] = pv[1]; // Q
5400  } else {
5401  // P = k, [P, Q] contains [k, l] (-+0-).
5402  types[0] = (int) TOUCHEDGE;
5403  pos[0] = pu[2]; // [C, A]
5404  pos[1] = pv[0]; // P
5405  types[1] = (int) ACROSSEDGE;
5406  pos[2] = pu[1]; // [B, C]
5407  pos[3] = pv[0]; // [P, Q]
5408  }
5409  }
5410  } else { // s3 < 0
5411  if (s2 > 0) {
5412  if (s4 > 0) {
5413  // [P, Q] in [k, l] (-+-+).
5414  types[0] = (int) TOUCHFACE;
5415  pos[0] = 3; // [A, B, C]
5416  pos[1] = pv[0]; // P
5417  types[1] = (int) TOUCHFACE;
5418  pos[2] = 3; // [A, B, C]
5419  pos[3] = pv[1]; // Q
5420  } else {
5421  if (s4 == 0) {
5422  // Q = l, [P, Q] in [k, l] (-+-0).
5423  types[0] = (int) TOUCHFACE;
5424  pos[0] = 3; // [A, B, C]
5425  pos[1] = pv[0]; // P
5426  types[1] = (int) TOUCHEDGE;
5427  pos[2] = pu[1]; // [B, C]
5428  pos[3] = pv[1]; // Q
5429  } else { // s4 < 0
5430  // [P, Q] overlaps [k, l] (-+--).
5431  types[0] = (int) TOUCHFACE;
5432  pos[0] = 3; // [A, B, C]
5433  pos[1] = pv[0]; // P
5434  types[1] = (int) ACROSSEDGE;
5435  pos[2] = pu[1]; // [B, C]
5436  pos[3] = pv[0]; // [P, Q]
5437  }
5438  }
5439  } else { // s2 == 0
5440  // P = l (#0##).
5441  types[0] = (int) TOUCHEDGE;
5442  pos[0] = pu[1]; // [B, C]
5443  pos[1] = pv[0]; // P
5444  types[1] = (int) DISJOINT;
5445  }
5446  }
5447  }
5448  } else { // s1 == 0
5449  // Q = k (0####)
5450  types[0] = (int) TOUCHEDGE;
5451  pos[0] = pu[2]; // [C, A]
5452  pos[1] = pv[1]; // Q
5453  types[1] = (int) DISJOINT;
5454  }
5455  } else if (z1 == 2) { // (tritri-23)
5456  if (s1 < 0) {
5457  if (s3 > 0) {
5458  if (s4 > 0) {
5459  // [P, Q] overlaps [A, l] (-+++).
5460  types[0] = (int) ACROSSVERT;
5461  pos[0] = pu[0]; // A
5462  pos[1] = pv[0]; // [P, Q]
5463  types[1] = (int) TOUCHFACE;
5464  pos[2] = 3; // [A, B, C]
5465  pos[3] = pv[1]; // Q
5466  } else {
5467  if (s4 == 0) {
5468  // Q = l, [P, Q] contains [A, l] (-++0).
5469  types[0] = (int) ACROSSVERT;
5470  pos[0] = pu[0]; // A
5471  pos[1] = pv[0]; // [P, Q]
5472  types[1] = (int) TOUCHEDGE;
5473  pos[2] = pu[1]; // [B, C]
5474  pos[3] = pv[1]; // Q
5475  } else { // s4 < 0
5476  // [P, Q] contains [A, l] (-++-).
5477  types[0] = (int) ACROSSVERT;
5478  pos[0] = pu[0]; // A
5479  pos[1] = pv[0]; // [P, Q]
5480  types[1] = (int) ACROSSEDGE;
5481  pos[2] = pu[1]; // [B, C]
5482  pos[3] = pv[0]; // [P, Q]
5483  }
5484  }
5485  } else {
5486  if (s3 == 0) {
5487  if (s4 > 0) {
5488  // P = A, [P, Q] in [A, l] (-+0+).
5489  types[0] = (int) SHAREVERT;
5490  pos[0] = pu[0]; // A
5491  pos[1] = pv[0]; // P
5492  types[1] = (int) TOUCHFACE;
5493  pos[2] = 3; // [A, B, C]
5494  pos[3] = pv[1]; // Q
5495  } else {
5496  if (s4 == 0) {
5497  // [P, Q] = [A, l] (-+00).
5498  types[0] = (int) SHAREVERT;
5499  pos[0] = pu[0]; // A
5500  pos[1] = pv[0]; // P
5501  types[1] = (int) TOUCHEDGE;
5502  pos[2] = pu[1]; // [B, C]
5503  pos[3] = pv[1]; // Q
5504  } else { // s4 < 0
5505  // Q = l, [P, Q] in [A, l] (-+0-).
5506  types[0] = (int) SHAREVERT;
5507  pos[0] = pu[0]; // A
5508  pos[1] = pv[0]; // P
5509  types[1] = (int) ACROSSEDGE;
5510  pos[2] = pu[1]; // [B, C]
5511  pos[3] = pv[0]; // [P, Q]
5512  }
5513  }
5514  } else { // s3 < 0
5515  if (s2 > 0) {
5516  if (s4 > 0) {
5517  // [P, Q] in [A, l] (-+-+).
5518  types[0] = (int) TOUCHFACE;
5519  pos[0] = 3; // [A, B, C]
5520  pos[1] = pv[0]; // P
5521  types[0] = (int) TOUCHFACE;
5522  pos[0] = 3; // [A, B, C]
5523  pos[1] = pv[1]; // Q
5524  } else {
5525  if (s4 == 0) {
5526  // Q = l, [P, Q] in [A, l] (-+-0).
5527  types[0] = (int) TOUCHFACE;
5528  pos[0] = 3; // [A, B, C]
5529  pos[1] = pv[0]; // P
5530  types[0] = (int) TOUCHEDGE;
5531  pos[0] = pu[1]; // [B, C]
5532  pos[1] = pv[1]; // Q
5533  } else { // s4 < 0
5534  // [P, Q] overlaps [A, l] (-+--).
5535  types[0] = (int) TOUCHFACE;
5536  pos[0] = 3; // [A, B, C]
5537  pos[1] = pv[0]; // P
5538  types[0] = (int) ACROSSEDGE;
5539  pos[0] = pu[1]; // [B, C]
5540  pos[1] = pv[0]; // [P, Q]
5541  }
5542  }
5543  } else { // s2 == 0
5544  // P = l (#0##).
5545  types[0] = (int) TOUCHEDGE;
5546  pos[0] = pu[1]; // [B, C]
5547  pos[1] = pv[0]; // P
5548  types[1] = (int) DISJOINT;
5549  }
5550  }
5551  }
5552  } else { // s1 == 0
5553  // Q = A (0###).
5554  types[0] = (int) SHAREVERT;
5555  pos[0] = pu[0]; // A
5556  pos[1] = pv[1]; // Q
5557  types[1] = (int) DISJOINT;
5558  }
5559  } else if (z1 == 3) { // (tritri-33)
5560  if (s1 < 0) {
5561  if (s3 > 0) {
5562  if (s4 > 0) {
5563  // [P, Q] overlaps [A, B] (-+++).
5564  types[0] = (int) ACROSSVERT;
5565  pos[0] = pu[0]; // A
5566  pos[1] = pv[0]; // [P, Q]
5567  types[1] = (int) TOUCHEDGE;
5568  pos[2] = pu[0]; // [A, B]
5569  pos[3] = pv[1]; // Q
5570  } else {
5571  if (s4 == 0) {
5572  // Q = B, [P, Q] contains [A, B] (-++0).
5573  types[0] = (int) ACROSSVERT;
5574  pos[0] = pu[0]; // A
5575  pos[1] = pv[0]; // [P, Q]
5576  types[1] = (int) SHAREVERT;
5577  pos[2] = pu[1]; // B
5578  pos[3] = pv[1]; // Q
5579  } else { // s4 < 0
5580  // [P, Q] contains [A, B] (-++-).
5581  types[0] = (int) ACROSSVERT;
5582  pos[0] = pu[0]; // A
5583  pos[1] = pv[0]; // [P, Q]
5584  types[1] = (int) ACROSSVERT;
5585  pos[2] = pu[1]; // B
5586  pos[3] = pv[0]; // [P, Q]
5587  }
5588  }
5589  } else {
5590  if (s3 == 0) {
5591  if (s4 > 0) {
5592  // P = A, [P, Q] in [A, B] (-+0+).
5593  types[0] = (int) SHAREVERT;
5594  pos[0] = pu[0]; // A
5595  pos[1] = pv[0]; // P
5596  types[1] = (int) TOUCHEDGE;
5597  pos[2] = pu[0]; // [A, B]
5598  pos[3] = pv[1]; // Q
5599  } else {
5600  if (s4 == 0) {
5601  // [P, Q] = [A, B] (-+00).
5602  types[0] = (int) SHAREEDGE;
5603  pos[0] = pu[0]; // [A, B]
5604  pos[1] = pv[0]; // [P, Q]
5605  types[1] = (int) DISJOINT;
5606  } else { // s4 < 0
5607  // P= A, [P, Q] in [A, B] (-+0-).
5608  types[0] = (int) SHAREVERT;
5609  pos[0] = pu[0]; // A
5610  pos[1] = pv[0]; // P
5611  types[1] = (int) ACROSSVERT;
5612  pos[2] = pu[1]; // B
5613  pos[3] = pv[0]; // [P, Q]
5614  }
5615  }
5616  } else { // s3 < 0
5617  if (s2 > 0) {
5618  if (s4 > 0) {
5619  // [P, Q] in [A, B] (-+-+).
5620  types[0] = (int) TOUCHEDGE;
5621  pos[0] = pu[0]; // [A, B]
5622  pos[1] = pv[0]; // P
5623  types[1] = (int) TOUCHEDGE;
5624  pos[2] = pu[0]; // [A, B]
5625  pos[3] = pv[1]; // Q
5626  } else {
5627  if (s4 == 0) {
5628  // Q = B, [P, Q] in [A, B] (-+-0).
5629  types[0] = (int) TOUCHEDGE;
5630  pos[0] = pu[0]; // [A, B]
5631  pos[1] = pv[0]; // P
5632  types[1] = (int) SHAREVERT;
5633  pos[2] = pu[1]; // B
5634  pos[3] = pv[1]; // Q
5635  } else { // s4 < 0
5636  // [P, Q] overlaps [A, B] (-+--).
5637  types[0] = (int) TOUCHEDGE;
5638  pos[0] = pu[0]; // [A, B]
5639  pos[1] = pv[0]; // P
5640  types[1] = (int) ACROSSVERT;
5641  pos[2] = pu[1]; // B
5642  pos[3] = pv[0]; // [P, Q]
5643  }
5644  }
5645  } else { // s2 == 0
5646  // P = B (#0##).
5647  types[0] = (int) SHAREVERT;
5648  pos[0] = pu[1]; // B
5649  pos[1] = pv[0]; // P
5650  types[1] = (int) DISJOINT;
5651  }
5652  }
5653  }
5654  } else { // s1 == 0
5655  // Q = A (0###).
5656  types[0] = (int) SHAREVERT;
5657  pos[0] = pu[0]; // A
5658  pos[1] = pv[1]; // Q
5659  types[1] = (int) DISJOINT;
5660  }
5661  }
5662 
5663  return 4;
5664 }
5665 
5666 int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
5667  REAL sP,REAL sQ,int level,int *types,int *pos)
5668 {
5669  point U[3], V[3]; //, Ptmp;
5670  int pu[3], pv[3]; //, itmp;
5671  REAL s1, s2, s3;
5672  int z1;
5673 
5674 
5675  if (sP < 0) {
5676  if (sQ < 0) { // (--) disjoint
5677  return 0;
5678  } else {
5679  if (sQ > 0) { // (-+)
5680  SETVECTOR3(U, A, B, C);
5681  SETVECTOR3(V, P, Q, R);
5682  SETVECTOR3(pu, 0, 1, 2);
5683  SETVECTOR3(pv, 0, 1, 2);
5684  z1 = 0;
5685  } else { // (-0)
5686  SETVECTOR3(U, A, B, C);
5687  SETVECTOR3(V, P, Q, R);
5688  SETVECTOR3(pu, 0, 1, 2);
5689  SETVECTOR3(pv, 0, 1, 2);
5690  z1 = 1;
5691  }
5692  }
5693  } else {
5694  if (sP > 0) { // (+-)
5695  if (sQ < 0) {
5696  SETVECTOR3(U, A, B, C);
5697  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5698  SETVECTOR3(pu, 0, 1, 2);
5699  SETVECTOR3(pv, 1, 0, 2);
5700  z1 = 0;
5701  } else {
5702  if (sQ > 0) { // (++) disjoint
5703  return 0;
5704  } else { // (+0)
5705  SETVECTOR3(U, B, A, C); // A and B are flipped.
5706  SETVECTOR3(V, P, Q, R);
5707  SETVECTOR3(pu, 1, 0, 2);
5708  SETVECTOR3(pv, 0, 1, 2);
5709  z1 = 1;
5710  }
5711  }
5712  } else { // sP == 0
5713  if (sQ < 0) { // (0-)
5714  SETVECTOR3(U, A, B, C);
5715  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5716  SETVECTOR3(pu, 0, 1, 2);
5717  SETVECTOR3(pv, 1, 0, 2);
5718  z1 = 1;
5719  } else {
5720  if (sQ > 0) { // (0+)
5721  SETVECTOR3(U, B, A, C); // A and B are flipped.
5722  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5723  SETVECTOR3(pu, 1, 0, 2);
5724  SETVECTOR3(pv, 1, 0, 2);
5725  z1 = 1;
5726  } else { // (00)
5727  // A, B, C, P, and Q are coplanar.
5728  z1 = 2;
5729  }
5730  }
5731  }
5732  }
5733 
5734  if (z1 == 2) {
5735  // The triangle and the edge are coplanar.
5736  return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
5737  }
5738 
5739  s1 = orient3d(U[0], U[1], V[0], V[1]);
5740  if (s1 < 0) {
5741  return 0;
5742  }
5743 
5744  s2 = orient3d(U[1], U[2], V[0], V[1]);
5745  if (s2 < 0) {
5746  return 0;
5747  }
5748 
5749  s3 = orient3d(U[2], U[0], V[0], V[1]);
5750  if (s3 < 0) {
5751  return 0;
5752  }
5753 
5754  if (level == 0) {
5755  return 1; // The are intersected.
5756  }
5757 
5758  types[1] = (int) DISJOINT; // No second intersection point.
5759 
5760  if (z1 == 0) {
5761  if (s1 > 0) {
5762  if (s2 > 0) {
5763  if (s3 > 0) { // (+++)
5764  // [P, Q] passes interior of [A, B, C].
5765  types[0] = (int) ACROSSFACE;
5766  pos[0] = 3; // interior of [A, B, C]
5767  pos[1] = 0; // [P, Q]
5768  } else { // s3 == 0 (++0)
5769  // [P, Q] intersects [C, A].
5770  types[0] = (int) ACROSSEDGE;
5771  pos[0] = pu[2]; // [C, A]
5772  pos[1] = 0; // [P, Q]
5773  }
5774  } else { // s2 == 0
5775  if (s3 > 0) { // (+0+)
5776  // [P, Q] intersects [B, C].
5777  types[0] = (int) ACROSSEDGE;
5778  pos[0] = pu[1]; // [B, C]
5779  pos[1] = 0; // [P, Q]
5780  } else { // s3 == 0 (+00)
5781  // [P, Q] passes C.
5782  types[0] = (int) ACROSSVERT;
5783  pos[0] = pu[2]; // C
5784  pos[1] = 0; // [P, Q]
5785  }
5786  }
5787  } else { // s1 == 0
5788  if (s2 > 0) {
5789  if (s3 > 0) { // (0++)
5790  // [P, Q] intersects [A, B].
5791  types[0] = (int) ACROSSEDGE;
5792  pos[0] = pu[0]; // [A, B]
5793  pos[1] = 0; // [P, Q]
5794  } else { // s3 == 0 (0+0)
5795  // [P, Q] passes A.
5796  types[0] = (int) ACROSSVERT;
5797  pos[0] = pu[0]; // A
5798  pos[1] = 0; // [P, Q]
5799  }
5800  } else { // s2 == 0
5801  if (s3 > 0) { // (00+)
5802  // [P, Q] passes B.
5803  types[0] = (int) ACROSSVERT;
5804  pos[0] = pu[1]; // B
5805  pos[1] = 0; // [P, Q]
5806  }
5807  }
5808  }
5809  } else { // z1 == 1
5810  if (s1 > 0) {
5811  if (s2 > 0) {
5812  if (s3 > 0) { // (+++)
5813  // Q lies in [A, B, C].
5814  types[0] = (int) TOUCHFACE;
5815  pos[0] = 0; // [A, B, C]
5816  pos[1] = pv[1]; // Q
5817  } else { // s3 == 0 (++0)
5818  // Q lies on [C, A].
5819  types[0] = (int) TOUCHEDGE;
5820  pos[0] = pu[2]; // [C, A]
5821  pos[1] = pv[1]; // Q
5822  }
5823  } else { // s2 == 0
5824  if (s3 > 0) { // (+0+)
5825  // Q lies on [B, C].
5826  types[0] = (int) TOUCHEDGE;
5827  pos[0] = pu[1]; // [B, C]
5828  pos[1] = pv[1]; // Q
5829  } else { // s3 == 0 (+00)
5830  // Q = C.
5831  types[0] = (int) SHAREVERT;
5832  pos[0] = pu[2]; // C
5833  pos[1] = pv[1]; // Q
5834  }
5835  }
5836  } else { // s1 == 0
5837  if (s2 > 0) {
5838  if (s3 > 0) { // (0++)
5839  // Q lies on [A, B].
5840  types[0] = (int) TOUCHEDGE;
5841  pos[0] = pu[0]; // [A, B]
5842  pos[1] = pv[1]; // Q
5843  } else { // s3 == 0 (0+0)
5844  // Q = A.
5845  types[0] = (int) SHAREVERT;
5846  pos[0] = pu[0]; // A
5847  pos[1] = pv[1]; // Q
5848  }
5849  } else { // s2 == 0
5850  if (s3 > 0) { // (00+)
5851  // Q = B.
5852  types[0] = (int) SHAREVERT;
5853  pos[0] = pu[1]; // B
5854  pos[1] = pv[1]; // Q
5855  }
5856  }
5857  }
5858  }
5859 
5860  // T and E intersect in a single point.
5861  return 2;
5862 }
5863 
5864 int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q,
5865  point R, int level, int *types, int *pos)
5866 {
5867  REAL sP, sQ;
5868 
5869  // Test the locations of P and Q with respect to ABC.
5870  sP = orient3d(A, B, C, P);
5871  sQ = orient3d(A, B, C, Q);
5872 
5873  return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
5874 }
5875 
5877 // //
5878 // tri_tri_inter() Test whether two triangle (abc) and (opq) are //
5879 // intersecting or not. //
5880 // //
5881 // Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
5882 // the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT. //
5883 // //
5885 
5886 int tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P,
5887  REAL* Q, REAL s_p, REAL s_q)
5888 {
5889  int types[2], pos[4];
5890  int ni; // =0, 2, 4
5891 
5892  ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
5893 
5894  if (ni > 0) {
5895  if (ni == 2) {
5896  // Get the intersection type.
5897  if (types[0] == (int) SHAREVERT) {
5898  return (int) SHAREVERT;
5899  } else {
5900  return (int) INTERSECT;
5901  }
5902  } else if (ni == 4) {
5903  // There may be two intersections.
5904  if (types[0] == (int) SHAREVERT) {
5905  if (types[1] == (int) DISJOINT) {
5906  return (int) SHAREVERT;
5907  } else {
5908  return (int) INTERSECT;
5909  }
5910  } else {
5911  if (types[0] == (int) SHAREEDGE) {
5912  return (int) SHAREEDGE;
5913  } else {
5914  return (int) INTERSECT;
5915  }
5916  }
5917  }
5918  }
5919 
5920  return (int) DISJOINT;
5921 }
5922 
5923 int tetgenmesh::tri_tri_inter(REAL* A,REAL* B,REAL* C,REAL* O,REAL* P,REAL* Q)
5924 {
5925  REAL s_o, s_p, s_q;
5926  REAL s_a, s_b, s_c;
5927 
5928  s_o = orient3d(A, B, C, O);
5929  s_p = orient3d(A, B, C, P);
5930  s_q = orient3d(A, B, C, Q);
5931  if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
5932  // o, p, q are all in the same halfspace of ABC.
5933  return 0; // DISJOINT;
5934  }
5935 
5936  s_a = orient3d(O, P, Q, A);
5937  s_b = orient3d(O, P, Q, B);
5938  s_c = orient3d(O, P, Q, C);
5939  if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
5940  // a, b, c are all in the same halfspace of OPQ.
5941  return 0; // DISJOINT;
5942  }
5943 
5944  int abcop, abcpq, abcqo;
5945  int shareedge = 0;
5946 
5947  abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
5948  if (abcop == (int) INTERSECT) {
5949  return (int) INTERSECT;
5950  } else if (abcop == (int) SHAREEDGE) {
5951  shareedge++;
5952  }
5953  abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
5954  if (abcpq == (int) INTERSECT) {
5955  return (int) INTERSECT;
5956  } else if (abcpq == (int) SHAREEDGE) {
5957  shareedge++;
5958  }
5959  abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
5960  if (abcqo == (int) INTERSECT) {
5961  return (int) INTERSECT;
5962  } else if (abcqo == (int) SHAREEDGE) {
5963  shareedge++;
5964  }
5965  if (shareedge == 3) {
5966  // opq are coincident with abc.
5967  return (int) SHAREFACE;
5968  }
5969 
5970  // Continue to detect whether opq and abc are intersecting or not.
5971  int opqab, opqbc, opqca;
5972 
5973  opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
5974  if (opqab == (int) INTERSECT) {
5975  return (int) INTERSECT;
5976  }
5977  opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
5978  if (opqbc == (int) INTERSECT) {
5979  return (int) INTERSECT;
5980  }
5981  opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
5982  if (opqca == (int) INTERSECT) {
5983  return (int) INTERSECT;
5984  }
5985 
5986  // At this point, two triangles are not intersecting and not coincident.
5987  // They may be share an edge, or share a vertex, or disjoint.
5988  if (abcop == (int) SHAREEDGE) {
5989  // op is coincident with an edge of abc.
5990  return (int) SHAREEDGE;
5991  }
5992  if (abcpq == (int) SHAREEDGE) {
5993  // pq is coincident with an edge of abc.
5994  return (int) SHAREEDGE;
5995  }
5996  if (abcqo == (int) SHAREEDGE) {
5997  // qo is coincident with an edge of abc.
5998  return (int) SHAREEDGE;
5999  }
6000 
6001  // They may share a vertex or disjoint.
6002  if (abcop == (int) SHAREVERT) {
6003  return (int) SHAREVERT;
6004  }
6005  if (abcpq == (int) SHAREVERT) {
6006  // q is the coincident vertex.
6007  return (int) SHAREVERT;
6008  }
6009 
6010  // They are disjoint.
6011  return (int) DISJOINT;
6012 }
6013 
6015 // //
6016 // lu_decmp() Compute the LU decomposition of a matrix. //
6017 // //
6018 // Compute the LU decomposition of a (non-singular) square matrix A using //
6019 // partial pivoting and implicit row exchanges. The result is: //
6020 // A = P * L * U, //
6021 // where P is a permutation matrix, L is unit lower triangular, and U is //
6022 // upper triangular. The factored form of A is used in combination with //
6023 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
6024 // //
6025 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
6026 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
6027 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
6028 // permutation effected by the partial pivoting, effectively, 'ps' array //
6029 // tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
6030 // depending on whether the number of row interchanges was even or odd, //
6031 // respectively. //
6032 // //
6033 // Return true if the LU decomposition is successfully computed, otherwise, //
6034 // return false in case that A is a singular matrix. //
6035 // //
6037 
6038 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6039 {
6040  REAL scales[4];
6041  REAL pivot, biggest, mult, tempf;
6042  int pivotindex = 0;
6043  int i, j, k;
6044 
6045  *d = 1.0; // No row interchanges yet.
6046 
6047  for (i = N; i < n + N; i++) { // For each row.
6048  // Find the largest element in each row for row equilibration
6049  biggest = 0.0;
6050  for (j = N; j < n + N; j++)
6051  if (biggest < (tempf = fabs(lu[i][j])))
6052  biggest = tempf;
6053  if (biggest != 0.0)
6054  scales[i] = 1.0 / biggest;
6055  else {
6056  scales[i] = 0.0;
6057  return false; // Zero row: singular matrix.
6058  }
6059  ps[i] = i; // Initialize pivot sequence.
6060  }
6061 
6062  for (k = N; k < n + N - 1; k++) { // For each column.
6063  // Find the largest element in each column to pivot around.
6064  biggest = 0.0;
6065  for (i = k; i < n + N; i++) {
6066  if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6067  biggest = tempf;
6068  pivotindex = i;
6069  }
6070  }
6071  if (biggest == 0.0) {
6072  return false; // Zero column: singular matrix.
6073  }
6074  if (pivotindex != k) { // Update pivot sequence.
6075  j = ps[k];
6076  ps[k] = ps[pivotindex];
6077  ps[pivotindex] = j;
6078  *d = -(*d); // ...and change the parity of d.
6079  }
6080 
6081  // Pivot, eliminating an extra variable each time
6082  pivot = lu[ps[k]][k];
6083  for (i = k + 1; i < n + N; i++) {
6084  lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6085  if (mult != 0.0) {
6086  for (j = k + 1; j < n + N; j++)
6087  lu[ps[i]][j] -= mult * lu[ps[k]][j];
6088  }
6089  }
6090  }
6091 
6092  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6093  return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6094 }
6095 
6097 // //
6098 // lu_solve() Solves the linear equation: Ax = b, after the matrix A //
6099 // has been decomposed into the lower and upper triangular //
6100 // matrices L and U, where A = LU. //
6101 // //
6102 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
6103 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
6104 // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
6105 // is input as the right-hand side vector, and returns with the solution //
6106 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
6107 // left in place for successive calls with different right-hand sides 'b'. //
6108 // //
6110 
6111 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6112 {
6113  int i, j;
6114  REAL X[4], dot;
6115 
6116  for (i = N; i < n + N; i++) X[i] = 0.0;
6117 
6118  // Vector reduction using U triangular matrix.
6119  for (i = N; i < n + N; i++) {
6120  dot = 0.0;
6121  for (j = N; j < i + N; j++)
6122  dot += lu[ps[i]][j] * X[j];
6123  X[i] = b[ps[i]] - dot;
6124  }
6125 
6126  // Back substitution, in L triangular matrix.
6127  for (i = n + N - 1; i >= N; i--) {
6128  dot = 0.0;
6129  for (j = i + 1; j < n + N; j++)
6130  dot += lu[ps[i]][j] * X[j];
6131  X[i] = (X[i] - dot) / lu[ps[i]][i];
6132  }
6133 
6134  for (i = N; i < n + N; i++) b[i] = X[i];
6135 }
6136 
6138 // //
6139 // incircle3d() 3D in-circle test. //
6140 // //
6141 // Return a negative value if pd is inside the circumcircle of the triangle //
6142 // pa, pb, and pc. //
6143 // //
6144 // IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input //
6145 // triangles are [a,b,c] and [b,a,d]. //
6146 // //
6148 
6149 REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
6150 {
6151  REAL area2[2], n1[3], n2[3], c[3];
6152  REAL sign, r, d;
6153 
6154  // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
6155  facenormal(pa, pb, pc, n1, 1, NULL);
6156  area2[0] = dot(n1, n1);
6157  facenormal(pb, pa, pd, n2, 1, NULL);
6158  area2[1] = dot(n2, n2);
6159 
6160  if (area2[0] > area2[1]) {
6161  // Choose [a, b, c] as the base triangle.
6162  circumsphere(pa, pb, pc, NULL, c, &r);
6163  d = distance(c, pd);
6164  } else {
6165  // Choose [b, a, d] as the base triangle.
6166  if (area2[1] > 0) {
6167  circumsphere(pb, pa, pd, NULL, c, &r);
6168  d = distance(c, pc);
6169  } else {
6170  // The four points are collinear. This case only happens on the boundary.
6171  return 0; // Return "not inside".
6172  }
6173  }
6174 
6175  sign = d - r;
6176  if (fabs(sign) / r < b->epsilon) {
6177  sign = 0;
6178  }
6179 
6180  return sign;
6181 }
6182 
6184 // //
6185 // facenormal() Calculate the normal of the face. //
6186 // //
6187 // The normal of the face abc can be calculated by the cross product of 2 of //
6188 // its 3 edge vectors. A better choice of two edge vectors will reduce the //
6189 // numerical error during the calculation. Burdakov proved that the optimal //
6190 // basis problem is equivalent to the minimum spanning tree problem with the //
6191 // edge length be the functional, see Burdakov, "A greedy algorithm for the //
6192 // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
6193 // short edges in abc are chosen for the calculation. //
6194 // //
6195 // If 'lav' is not NULL and if 'pivot' is set, the average edge length of //
6196 // the edges of the face [a,b,c] is returned. //
6197 // //
6199 
6200 void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
6201  REAL* lav)
6202 {
6203  REAL v1[3], v2[3], v3[3], *pv1, *pv2;
6204  REAL L1, L2, L3;
6205 
6206  v1[0] = pb[0] - pa[0]; // edge vector v1: a->b
6207  v1[1] = pb[1] - pa[1];
6208  v1[2] = pb[2] - pa[2];
6209  v2[0] = pa[0] - pc[0]; // edge vector v2: c->a
6210  v2[1] = pa[1] - pc[1];
6211  v2[2] = pa[2] - pc[2];
6212 
6213  // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
6214  if (pivot > 0) {
6215  // Choose edge vectors by Burdakov's algorithm.
6216  v3[0] = pc[0] - pb[0]; // edge vector v3: b->c
6217  v3[1] = pc[1] - pb[1];
6218  v3[2] = pc[2] - pb[2];
6219  L1 = dot(v1, v1);
6220  L2 = dot(v2, v2);
6221  L3 = dot(v3, v3);
6222  // Sort the three edge lengths.
6223  if (L1 < L2) {
6224  if (L2 < L3) {
6225  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6226  } else {
6227  pv1 = v3; pv2 = v1; // n = v3 x (-v1).
6228  }
6229  } else {
6230  if (L1 < L3) {
6231  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6232  } else {
6233  pv1 = v2; pv2 = v3; // n = v2 x (-v3).
6234  }
6235  }
6236  if (lav) {
6237  // return the average edge length.
6238  *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
6239  }
6240  } else {
6241  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6242  }
6243 
6244  // Calculate the face normal.
6245  cross(pv1, pv2, n);
6246  // Inverse the direction;
6247  n[0] = -n[0];
6248  n[1] = -n[1];
6249  n[2] = -n[2];
6250 }
6251 
6253 // //
6254 // shortdistance() Returns the shortest distance from point p to a line //
6255 // defined by two points e1 and e2. //
6256 // //
6257 // First compute the projection length l_p of the vector v1 = p - e1 along //
6258 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
6259 // shortest distance. //
6260 // //
6261 // This routine allows that p is collinear with the line. In this case, the //
6262 // return value is zero. The two points e1 and e2 should not be identical. //
6263 // //
6265 
6266 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
6267 {
6268  REAL v1[3], v2[3];
6269  REAL len, l_p;
6270 
6271  v1[0] = e2[0] - e1[0];
6272  v1[1] = e2[1] - e1[1];
6273  v1[2] = e2[2] - e1[2];
6274  v2[0] = p[0] - e1[0];
6275  v2[1] = p[1] - e1[1];
6276  v2[2] = p[2] - e1[2];
6277 
6278  len = sqrt(dot(v1, v1));
6279 
6280  v1[0] /= len;
6281  v1[1] /= len;
6282  v1[2] /= len;
6283  l_p = dot(v1, v2);
6284 
6285  return sqrt(dot(v2, v2) - l_p * l_p);
6286 }
6287 
6289 // //
6290 // triarea() Return the area of a triangle. //
6291 // //
6293 
6294 REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
6295 {
6296  REAL A[4][4];
6297 
6298  // Compute the coefficient matrix A (3x3).
6299  A[0][0] = pb[0] - pa[0];
6300  A[0][1] = pb[1] - pa[1];
6301  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
6302  A[1][0] = pc[0] - pa[0];
6303  A[1][1] = pc[1] - pa[1];
6304  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
6305 
6306  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
6307 
6308  return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
6309 }
6310 
6311 REAL tetgenmesh::orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
6312 {
6313  REAL adx, bdx, cdx;
6314  REAL ady, bdy, cdy;
6315  REAL adz, bdz, cdz;
6316 
6317  adx = pa[0] - pd[0];
6318  bdx = pb[0] - pd[0];
6319  cdx = pc[0] - pd[0];
6320  ady = pa[1] - pd[1];
6321  bdy = pb[1] - pd[1];
6322  cdy = pc[1] - pd[1];
6323  adz = pa[2] - pd[2];
6324  bdz = pb[2] - pd[2];
6325  cdz = pc[2] - pd[2];
6326 
6327  return adx * (bdy * cdz - bdz * cdy)
6328  + bdx * (cdy * adz - cdz * ady)
6329  + cdx * (ady * bdz - adz * bdy);
6330 }
6331 
6333 // //
6334 // interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
6335 // o->p1 and o->p2. //
6336 // //
6337 // 'n' is the normal of the plane containing face (o, p1, p2). The interior //
6338 // angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
6339 // the position of p1 and p2 will get the complement angle of the other one. //
6340 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
6341 // 'n' be NULL if you only want the interior angle between 0 - PI. //
6342 // //
6344 
6345 REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
6346 {
6347  REAL v1[3], v2[3], np[3];
6348  REAL theta, costheta, lenlen;
6349  REAL ori, len1, len2;
6350 
6351  // Get the interior angle (0 - PI) between o->p1, and o->p2.
6352  v1[0] = p1[0] - o[0];
6353  v1[1] = p1[1] - o[1];
6354  v1[2] = p1[2] - o[2];
6355  v2[0] = p2[0] - o[0];
6356  v2[1] = p2[1] - o[1];
6357  v2[2] = p2[2] - o[2];
6358  len1 = sqrt(dot(v1, v1));
6359  len2 = sqrt(dot(v2, v2));
6360  lenlen = len1 * len2;
6361 
6362  costheta = dot(v1, v2) / lenlen;
6363  if (costheta > 1.0) {
6364  costheta = 1.0; // Roundoff.
6365  } else if (costheta < -1.0) {
6366  costheta = -1.0; // Roundoff.
6367  }
6368  theta = acos(costheta);
6369  if (n != NULL) {
6370  // Get a point above the face (o, p1, p2);
6371  np[0] = o[0] + n[0];
6372  np[1] = o[1] + n[1];
6373  np[2] = o[2] + n[2];
6374  // Adjust theta (0 - 2 * PI).
6375  ori = orient3d(p1, o, np, p2);
6376  if (ori > 0.0) {
6377  theta = 2 * PI - theta;
6378  }
6379  }
6380 
6381  return theta;
6382 }
6383 
6385 // //
6386 // projpt2edge() Return the projection point from a point to an edge. //
6387 // //
6389 
6390 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
6391 {
6392  REAL v1[3], v2[3];
6393  REAL len, l_p;
6394 
6395  v1[0] = e2[0] - e1[0];
6396  v1[1] = e2[1] - e1[1];
6397  v1[2] = e2[2] - e1[2];
6398  v2[0] = p[0] - e1[0];
6399  v2[1] = p[1] - e1[1];
6400  v2[2] = p[2] - e1[2];
6401 
6402  len = sqrt(dot(v1, v1));
6403  v1[0] /= len;
6404  v1[1] /= len;
6405  v1[2] /= len;
6406  l_p = dot(v1, v2);
6407 
6408  prj[0] = e1[0] + l_p * v1[0];
6409  prj[1] = e1[1] + l_p * v1[1];
6410  prj[2] = e1[2] + l_p * v1[2];
6411 }
6412 
6414 // //
6415 // projpt2face() Return the projection point from a point to a face. //
6416 // //
6418 
6419 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
6420 {
6421  REAL fnormal[3], v1[3];
6422  REAL len, dist;
6423 
6424  // Get the unit face normal.
6425  facenormal(f1, f2, f3, fnormal, 1, NULL);
6426  len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] +
6427  fnormal[2]*fnormal[2]);
6428  fnormal[0] /= len;
6429  fnormal[1] /= len;
6430  fnormal[2] /= len;
6431  // Get the vector v1 = |p - f1|.
6432  v1[0] = p[0] - f1[0];
6433  v1[1] = p[1] - f1[1];
6434  v1[2] = p[2] - f1[2];
6435  // Get the project distance.
6436  dist = dot(fnormal, v1);
6437 
6438  // Get the project point.
6439  prj[0] = p[0] - dist * fnormal[0];
6440  prj[1] = p[1] - dist * fnormal[1];
6441  prj[2] = p[2] - dist * fnormal[2];
6442 }
6443 
6445 // //
6446 // tetalldihedral() Get all (six) dihedral angles of a tet. //
6447 // //
6448 // If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles, //
6449 // the edge indices are given in the global array 'edge2ver'. If 'cosmaxd' //
6450 // (or 'cosmind') is not NULL, it returns the cosine of the maximal (or //
6451 // minimal) dihedral angle. //
6452 // //
6454 
6455 bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
6456  REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
6457 {
6458  REAL N[4][3], vol, cosd, len;
6459  int f1 = 0, f2 = 0, i, j;
6460 
6461  vol = 0; // Check if the tet is valid or not.
6462 
6463  // Get four normals of faces of the tet.
6464  tetallnormal(pa, pb, pc, pd, N, &vol);
6465 
6466  if (vol > 0) {
6467  // Normalize the normals.
6468  for (i = 0; i < 4; i++) {
6469  len = sqrt(dot(N[i], N[i]));
6470  if (len != 0.0) {
6471  for (j = 0; j < 3; j++) N[i][j] /= len;
6472  } else {
6473  // There are degeneracies, such as duplicated vertices.
6474  vol = 0; //assert(0);
6475  }
6476  }
6477  }
6478 
6479  if (vol <= 0) { // if (vol == 0.0) {
6480  // A degenerated tet or an inverted tet.
6481  facenormal(pc, pb, pd, N[0], 1, NULL);
6482  facenormal(pa, pc, pd, N[1], 1, NULL);
6483  facenormal(pb, pa, pd, N[2], 1, NULL);
6484  facenormal(pa, pb, pc, N[3], 1, NULL);
6485  // Normalize the normals.
6486  for (i = 0; i < 4; i++) {
6487  len = sqrt(dot(N[i], N[i]));
6488  if (len != 0.0) {
6489  for (j = 0; j < 3; j++) N[i][j] /= len;
6490  } else {
6491  // There are degeneracies, such as duplicated vertices.
6492  break; // Not a valid normal.
6493  }
6494  }
6495  if (i < 4) {
6496  // Do not calculate dihedral angles.
6497  // Set all angles be 0 degree. There will be no quality optimization for
6498  // this tet! Use volume optimization to correct it.
6499  if (cosdd != NULL) {
6500  for (i = 0; i < 6; i++) {
6501  cosdd[i] = -1.0; // 180 degree.
6502  }
6503  }
6504  // This tet has zero volume.
6505  if (cosmaxd != NULL) {
6506  *cosmaxd = -1.0; // 180 degree.
6507  }
6508  if (cosmind != NULL) {
6509  *cosmind = -1.0; // 180 degree.
6510  }
6511  return false;
6512  }
6513  }
6514 
6515  // Calculate the cosine of the dihedral angles of the edges.
6516  for (i = 0; i < 6; i++) {
6517  switch (i) {
6518  case 0: f1 = 0; f2 = 1; break; // [c,d].
6519  case 1: f1 = 1; f2 = 2; break; // [a,d].
6520  case 2: f1 = 2; f2 = 3; break; // [a,b].
6521  case 3: f1 = 0; f2 = 3; break; // [b,c].
6522  case 4: f1 = 2; f2 = 0; break; // [b,d].
6523  case 5: f1 = 1; f2 = 3; break; // [a,c].
6524  }
6525  cosd = -dot(N[f1], N[f2]);
6526  if (cosd < -1.0) cosd = -1.0; // Rounding.
6527  if (cosd > 1.0) cosd = 1.0; // Rounding.
6528  if (cosdd) cosdd[i] = cosd;
6529  if (cosmaxd || cosmind) {
6530  if (i == 0) {
6531  if (cosmaxd) *cosmaxd = cosd;
6532  if (cosmind) *cosmind = cosd;
6533  } else {
6534  if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
6535  if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
6536  }
6537  }
6538  }
6539 
6540  return true;
6541 }
6542 
6544 // //
6545 // tetallnormal() Get the in-normals of the four faces of a given tet. //
6546 // //
6547 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
6548 // N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices //
6549 // of the mesh data structure). These normals are unnormalized. //
6550 // //
6552 
6553 void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
6554  REAL N[4][3], REAL* volume)
6555 {
6556  REAL A[4][4], rhs[4], D;
6557  int indx[4];
6558  int i, j;
6559 
6560  // get the entries of A[3][3].
6561  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
6562  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
6563  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
6564 
6565  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
6566  if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
6567  if (volume != NULL) {
6568  // Get the volume of the tet.
6569  *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
6570  }
6571  for (j = 0; j < 3; j++) {
6572  for (i = 0; i < 3; i++) rhs[i] = 0.0;
6573  rhs[j] = 1.0; // Positive means the inside direction
6574  lu_solve(A, 3, indx, rhs, 0);
6575  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6576  }
6577  // Get the fourth normal by summing up the first three.
6578  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6579  } else {
6580  // The tet is degenerated.
6581  if (volume != NULL) {
6582  *volume = 0;
6583  }
6584  }
6585 }
6586 
6588 // //
6589 // tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
6590 // //
6591 // The aspect ratio of a tet is L/h, where L is the longest edge length, and //
6592 // h is the shortest height of the tet. //
6593 // //
6595 
6596 REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
6597 {
6598  REAL V[6][3], edgelength[6], longlen;
6599  REAL vda[3], vdb[3], vdc[3];
6600  REAL N[4][3], A[4][4], rhs[4], D;
6601  REAL H[4], volume, minheightinv;
6602  int indx[4];
6603  int i, j;
6604 
6605  // Set the edge vectors: V[0], ..., V[5]
6606  for (i = 0; i < 3; i++) V[0][i] = pa[i] - pd[i];
6607  for (i = 0; i < 3; i++) V[1][i] = pb[i] - pd[i];
6608  for (i = 0; i < 3; i++) V[2][i] = pc[i] - pd[i];
6609  for (i = 0; i < 3; i++) V[3][i] = pb[i] - pa[i];
6610  for (i = 0; i < 3; i++) V[4][i] = pc[i] - pb[i];
6611  for (i = 0; i < 3; i++) V[5][i] = pa[i] - pc[i];
6612 
6613  // Get the squares of the edge lengths.
6614  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
6615 
6616  // Calculate the longest and shortest edge length.
6617  longlen = edgelength[0];
6618  for (i = 1; i < 6; i++) {
6619  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
6620  }
6621 
6622  // Set the matrix A = [vda, vdb, vdc]^T.
6623  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
6624  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
6625  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
6626  // Lu-decompose the matrix A.
6627  lu_decmp(A, 3, indx, &D, 0);
6628  // Get the volume of abcd.
6629  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
6630  // Check if it is zero.
6631  if (volume == 0.0) return 1.0e+200; // A degenerate tet.
6632 
6633  // Compute the 4 face normals (N[0], ..., N[3]).
6634  for (j = 0; j < 3; j++) {
6635  for (i = 0; i < 3; i++) rhs[i] = 0.0;
6636  rhs[j] = 1.0; // Positive means the inside direction
6637  lu_solve(A, 3, indx, rhs, 0);
6638  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6639  }
6640  // Get the fourth normal by summing up the first three.
6641  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6642  // Normalized the normals.
6643  for (i = 0; i < 4; i++) {
6644  // H[i] is the inverse of the height of its corresponding face.
6645  H[i] = sqrt(dot(N[i], N[i]));
6646  // if (H[i] > 0.0) {
6647  // for (j = 0; j < 3; j++) N[i][j] /= H[i];
6648  // }
6649  }
6650  // Get the radius of the inscribed sphere.
6651  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
6652  // Get the biggest H[i] (corresponding to the smallest height).
6653  minheightinv = H[0];
6654  for (i = 1; i < 4; i++) {
6655  if (H[i] > minheightinv) minheightinv = H[i];
6656  }
6657 
6658  return sqrt(longlen) * minheightinv;
6659 }
6660 
6662 // //
6663 // circumsphere() Calculate the smallest circumsphere (center and radius) //
6664 // of the given three or four points. //
6665 // //
6666 // The circumsphere of four points (a tetrahedron) is unique if they are not //
6667 // degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
6668 // the diametral sphere of the triangle if they are not degenerate. //
6669 // //
6670 // Return TRUE if the input points are not degenerate and the circumcenter //
6671 // and circumradius are returned in 'cent' and 'radius' respectively if they //
6672 // are not NULLs. Otherwise, return FALSE, the four points are co-planar. //
6673 // //
6675 
6676 bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6677  REAL* cent, REAL* radius)
6678 {
6679  REAL A[4][4], rhs[4], D;
6680  int indx[4];
6681 
6682  // Compute the coefficient matrix A (3x3).
6683  A[0][0] = pb[0] - pa[0];
6684  A[0][1] = pb[1] - pa[1];
6685  A[0][2] = pb[2] - pa[2];
6686  A[1][0] = pc[0] - pa[0];
6687  A[1][1] = pc[1] - pa[1];
6688  A[1][2] = pc[2] - pa[2];
6689  if (pd != NULL) {
6690  A[2][0] = pd[0] - pa[0];
6691  A[2][1] = pd[1] - pa[1];
6692  A[2][2] = pd[2] - pa[2];
6693  } else {
6694  cross(A[0], A[1], A[2]);
6695  }
6696 
6697  // Compute the right hand side vector b (3x1).
6698  rhs[0] = 0.5 * dot(A[0], A[0]);
6699  rhs[1] = 0.5 * dot(A[1], A[1]);
6700  if (pd != NULL) {
6701  rhs[2] = 0.5 * dot(A[2], A[2]);
6702  } else {
6703  rhs[2] = 0.0;
6704  }
6705 
6706  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
6707  // and backward and forward substitute..
6708  if (!lu_decmp(A, 3, indx, &D, 0)) {
6709  if (radius != (REAL *) NULL) *radius = 0.0;
6710  return false;
6711  }
6712  lu_solve(A, 3, indx, rhs, 0);
6713  if (cent != (REAL *) NULL) {
6714  cent[0] = pa[0] + rhs[0];
6715  cent[1] = pa[1] + rhs[1];
6716  cent[2] = pa[2] + rhs[2];
6717  }
6718  if (radius != (REAL *) NULL) {
6719  *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
6720  }
6721  return true;
6722 }
6723 
6725 // //
6726 // orthosphere() Calulcate the orthosphere of four weighted points. //
6727 // //
6728 // A weighted point (p, P^2) can be interpreted as a sphere centered at the //
6729 // point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 + //
6730 // p[1]^2 + p[2]^2 - P^2. //
6731 // //
6733 
6734 bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6735  REAL aheight, REAL bheight, REAL cheight,
6736  REAL dheight, REAL* orthocent, REAL* radius)
6737 {
6738  REAL A[4][4], rhs[4], D;
6739  int indx[4];
6740 
6741  // Set the coefficient matrix A (4 x 4).
6742  A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
6743  A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
6744  A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
6745  A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
6746 
6747  // Set the right hand side vector (4 x 1).
6748  rhs[0] = 0.5 * aheight;
6749  rhs[1] = 0.5 * bheight;
6750  rhs[2] = 0.5 * cheight;
6751  rhs[3] = 0.5 * dheight;
6752 
6753  // Solve the 4 by 4 equations use LU decomposition with partial pivoting
6754  // and backward and forward substitute..
6755  if (!lu_decmp(A, 4, indx, &D, 0)) {
6756  if (radius != (REAL *) NULL) *radius = 0.0;
6757  return false;
6758  }
6759  lu_solve(A, 4, indx, rhs, 0);
6760 
6761  if (orthocent != (REAL *) NULL) {
6762  orthocent[0] = rhs[1];
6763  orthocent[1] = rhs[2];
6764  orthocent[2] = rhs[3];
6765  }
6766  if (radius != (REAL *) NULL) {
6767  // rhs[0] = - rheight / 2;
6768  // rheight = - 2 * rhs[0];
6769  // = r[0]^2 + r[1]^2 + r[2]^2 - radius^2
6770  // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
6771  // = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
6772  *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
6773  + 2.0 * rhs[0]);
6774  }
6775  return true;
6776 }
6777 
6778 void tetgenmesh::tetcircumcenter(point tetorg, point tetdest, point tetfapex,
6779  point tettapex, REAL *circumcenter, REAL *radius)
6780 {
6781  REAL xot, yot, zot, xdt, ydt, zdt, xft, yft, zft;
6782  REAL otlength, dtlength, ftlength;
6783  REAL xcrossdf, ycrossdf, zcrossdf;
6784  REAL xcrossfo, ycrossfo, zcrossfo;
6785  REAL xcrossod, ycrossod, zcrossod;
6786  REAL denominator;
6787  REAL xct, yct, zct;
6788 
6789  //tetcircumcentercount++;
6790 
6791  /* Use coordinates relative to the apex of the tetrahedron. */
6792  xot = tetorg[0] - tettapex[0];
6793  yot = tetorg[1] - tettapex[1];
6794  zot = tetorg[2] - tettapex[2];
6795  xdt = tetdest[0] - tettapex[0];
6796  ydt = tetdest[1] - tettapex[1];
6797  zdt = tetdest[2] - tettapex[2];
6798  xft = tetfapex[0] - tettapex[0];
6799  yft = tetfapex[1] - tettapex[1];
6800  zft = tetfapex[2] - tettapex[2];
6801  /* Squares of lengths of the origin, destination, and face apex edges. */
6802  otlength = xot * xot + yot * yot + zot * zot;
6803  dtlength = xdt * xdt + ydt * ydt + zdt * zdt;
6804  ftlength = xft * xft + yft * yft + zft * zft;
6805  /* Cross products of the origin, destination, and face apex vectors. */
6806  xcrossdf = ydt * zft - yft * zdt;
6807  ycrossdf = zdt * xft - zft * xdt;
6808  zcrossdf = xdt * yft - xft * ydt;
6809  xcrossfo = yft * zot - yot * zft;
6810  ycrossfo = zft * xot - zot * xft;
6811  zcrossfo = xft * yot - xot * yft;
6812  xcrossod = yot * zdt - ydt * zot;
6813  ycrossod = zot * xdt - zdt * xot;
6814  zcrossod = xot * ydt - xdt * yot;
6815 
6816  /* Calculate the denominator of all the formulae. */
6817  //if (noexact) {
6818  // denominator = 0.5 / (xot * xcrossdf + yot * ycrossdf + zot * zcrossdf);
6819  //} else {
6820  /* Use the orient3d() routine to ensure a positive (and */
6821  /* reasonably accurate) result, avoiding any possibility */
6822  /* of division by zero. */
6823  denominator = 0.5 / orient3d(tetorg, tetdest, tetfapex, tettapex);
6824  /* Don't count the above as an orientation test. */
6825  //orientcount--;
6826  //}
6827 
6828  /* Calculate offset (from apex) of circumcenter. */
6829  xct = (otlength * xcrossdf + dtlength * xcrossfo + ftlength * xcrossod) *
6830  denominator;
6831  yct = (otlength * ycrossdf + dtlength * ycrossfo + ftlength * ycrossod) *
6832  denominator;
6833  zct = (otlength * zcrossdf + dtlength * zcrossfo + ftlength * zcrossod) *
6834  denominator;
6835 
6836  circumcenter[0] = xct + tettapex[0];
6837  circumcenter[1] = yct + tettapex[1];
6838  circumcenter[2] = zct + tettapex[2];
6839 
6840  if (radius != NULL) {
6841  *radius = sqrt(xct * xct + yct * yct + zct * zct);
6842  }
6843 }
6844 
6846 // //
6847 // planelineint() Calculate the intersection of a line and a plane. //
6848 // //
6849 // The equation of a plane (points P are on the plane with normal N and P3 //
6850 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
6851 // line (points P on the line passing through P1 and P2) can be written as: //
6852 // P = P1 + u (P2 - P1). The intersection of these two occurs when: //
6853 // N dot (P1 + u (P2 - P1)) = N dot P3. //
6854 // Solving for u gives: //
6855 // N dot (P3 - P1) //
6856 // u = ------------------. //
6857 // N dot (P2 - P1) //
6858 // If the denominator is 0 then N (the normal to the plane) is perpendicular //
6859 // to the line. Thus the line is either parallel to the plane and there are //
6860 // no solutions or the line is on the plane in which case there are an infi- //
6861 // nite number of solutions. //
6862 // //
6863 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
6864 // line. If u is non-zero, The intersection point (if exists) returns in ip. //
6865 // //
6867 
6868 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
6869  REAL* ip, REAL* u)
6870 {
6871  REAL n[3], det, det1;
6872 
6873  // Calculate N.
6874  facenormal(pa, pb, pc, n, 1, NULL);
6875  // Calculate N dot (e2 - e1).
6876  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
6877  + n[2] * (e2[2] - e1[2]);
6878  if (det != 0.0) {
6879  // Calculate N dot (pa - e1)
6880  det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
6881  + n[2] * (pa[2] - e1[2]);
6882  *u = det1 / det;
6883  ip[0] = e1[0] + *u * (e2[0] - e1[0]);
6884  ip[1] = e1[1] + *u * (e2[1] - e1[1]);
6885  ip[2] = e1[2] + *u * (e2[2] - e1[2]);
6886  } else {
6887  *u = 0.0;
6888  }
6889 }
6890 
6892 // //
6893 // linelineint() Calculate the intersection(s) of two line segments. //
6894 // //
6895 // Calculate the line segment [P, Q] that is the shortest route between two //
6896 // lines from A to B and C to D. Calculate also the values of tp and tq //
6897 // where: P = A + tp (B - A), and Q = C + tq (D - C). //
6898 // //
6899 // Return 1 if the line segment exists. Otherwise, return 0. //
6900 // //
6902 
6903 int tetgenmesh::linelineint(REAL* A, REAL* B, REAL* C, REAL* D, REAL* P,
6904  REAL* Q, REAL* tp, REAL* tq)
6905 {
6906  REAL vab[3], vcd[3], vca[3];
6907  REAL vab_vab, vcd_vcd, vab_vcd;
6908  REAL vca_vab, vca_vcd;
6909  REAL det, eps;
6910  int i;
6911 
6912  for (i = 0; i < 3; i++) {
6913  vab[i] = B[i] - A[i];
6914  vcd[i] = D[i] - C[i];
6915  vca[i] = A[i] - C[i];
6916  }
6917 
6918  vab_vab = dot(vab, vab);
6919  vcd_vcd = dot(vcd, vcd);
6920  vab_vcd = dot(vab, vcd);
6921 
6922  det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
6923  // Round the result.
6924  eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
6925  if (eps < b->epsilon) {
6926  return 0;
6927  }
6928 
6929  vca_vab = dot(vca, vab);
6930  vca_vcd = dot(vca, vcd);
6931 
6932  *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
6933  *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
6934 
6935  for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
6936  for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
6937 
6938  return 1;
6939 }
6940 
6942 // //
6943 // tetprismvol() Calculate the volume of a tetrahedral prism in 4D. //
6944 // //
6945 // A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
6946 // tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular //
6947 // prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
6948 // vertices. (Wikipedia). //
6949 // //
6950 // Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
6951 // the lower tetrahedral facet of the prism. The top tetrahedral facet is //
6952 // formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by //
6953 // lifting each vertex of the lower facet into R^4 by a weight (height). A //
6954 // canonical choice of the weights is the square of Euclidean norm of of the //
6955 // points (vectors). //
6956 // //
6957 // //
6958 // The return value is (4!) 24 times of the volume of the tetrahedral prism. //
6959 // //
6961 
6962 REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
6963 {
6964  REAL *p4, *p5, *p6, *p7;
6965  REAL w4, w5, w6, w7;
6966  REAL vol[4];
6967 
6968  p4 = p0;
6969  p5 = p1;
6970  p6 = p2;
6971  p7 = p3;
6972 
6973  // TO DO: these weights can be pre-calculated!
6974  w4 = dot(p0, p0);
6975  w5 = dot(p1, p1);
6976  w6 = dot(p2, p2);
6977  w7 = dot(p3, p3);
6978 
6979  // Calculate the volume of the tet-prism.
6980  vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
6981  vol[1] = orient4d(p3, p6, p2, p0, p1, 0, w6, 0, 0, 0);
6982  vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6, 0, 0, 0);
6983  vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0, 0);
6984 
6985  return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
6986 }
6987 
6989 // //
6990 // calculateabovepoint() Calculate a point above a facet in 'dummypoint'. //
6991 // //
6993 
6994 bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
6995  point *ppb, point *ppc)
6996 {
6997  point *ppt, pa, pb, pc;
6998  REAL v1[3], v2[3], n[3];
6999  REAL lab, len, A, area;
7000  REAL x, y, z;
7001  int i;
7002 
7003  ppt = (point *) fastlookup(facpoints, 0);
7004  pa = *ppt; // a is the first point.
7005  pb = pc = NULL; // Avoid compiler warnings.
7006 
7007  // Get a point b s.t. the length of [a, b] is maximal.
7008  lab = 0;
7009  for (i = 1; i < facpoints->objects; i++) {
7010  ppt = (point *) fastlookup(facpoints, i);
7011  x = (*ppt)[0] - pa[0];
7012  y = (*ppt)[1] - pa[1];
7013  z = (*ppt)[2] - pa[2];
7014  len = x * x + y * y + z * z;
7015  if (len > lab) {
7016  lab = len;
7017  pb = *ppt;
7018  }
7019  }
7020  lab = sqrt(lab);
7021  if (lab == 0) {
7022  if (!b->quiet) {
7023  printf("Warning: All points of a facet are coincident with %d.\n",
7024  pointmark(pa));
7025  }
7026  return false;
7027  }
7028 
7029  // Get a point c s.t. the area of [a, b, c] is maximal.
7030  v1[0] = pb[0] - pa[0];
7031  v1[1] = pb[1] - pa[1];
7032  v1[2] = pb[2] - pa[2];
7033  A = 0;
7034  for (i = 1; i < facpoints->objects; i++) {
7035  ppt = (point *) fastlookup(facpoints, i);
7036  v2[0] = (*ppt)[0] - pa[0];
7037  v2[1] = (*ppt)[1] - pa[1];
7038  v2[2] = (*ppt)[2] - pa[2];
7039  cross(v1, v2, n);
7040  area = dot(n, n);
7041  if (area > A) {
7042  A = area;
7043  pc = *ppt;
7044  }
7045  }
7046  if (A == 0) {
7047  // All points are collinear. No above point.
7048  if (!b->quiet) {
7049  printf("Warning: All points of a facet are collinaer with [%d, %d].\n",
7050  pointmark(pa), pointmark(pb));
7051  }
7052  return false;
7053  }
7054 
7055  // Calculate an above point of this facet.
7056  facenormal(pa, pb, pc, n, 1, NULL);
7057  len = sqrt(dot(n, n));
7058  n[0] /= len;
7059  n[1] /= len;
7060  n[2] /= len;
7061  lab /= 2.0; // Half the maximal length.
7062  dummypoint[0] = pa[0] + lab * n[0];
7063  dummypoint[1] = pa[1] + lab * n[1];
7064  dummypoint[2] = pa[2] + lab * n[2];
7065 
7066  if (ppa != NULL) {
7067  // Return the three points.
7068  *ppa = pa;
7069  *ppb = pb;
7070  *ppc = pc;
7071  }
7072 
7073  return true;
7074 }
7075 
7077 // //
7078 // Calculate an above point. It lies above the plane containing the subface //
7079 // [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
7080 // is the normal of the plane. //
7081 // //
7083 
7084 void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
7085 {
7086  REAL n1[3], n2[3], *norm;
7087  REAL len, len1, len2;
7088 
7089  // Select a base.
7090  facenormal(pa, pb, pc, n1, 1, NULL);
7091  len1 = sqrt(dot(n1, n1));
7092  facenormal(pa, pb, pd, n2, 1, NULL);
7093  len2 = sqrt(dot(n2, n2));
7094  if (len1 > len2) {
7095  norm = n1;
7096  len = len1;
7097  } else {
7098  norm = n2;
7099  len = len2;
7100  }
7101  norm[0] /= len;
7102  norm[1] /= len;
7103  norm[2] /= len;
7104  len = distance(pa, pb);
7105  dummypoint[0] = pa[0] + len * norm[0];
7106  dummypoint[1] = pa[1] + len * norm[1];
7107  dummypoint[2] = pa[2] + len * norm[2];
7108 }
7109 
7111 // //
7112 // report_overlapping_facets() Report two overlapping facets. //
7113 // //
7114 // Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b]. //
7115 // 'dihedang' is the dihedral angle between these two facets. It must less //
7116 // than the variable 'b->facet_overlap_angle_tol'. //
7117 // //
7119 
7120 void tetgenmesh::report_overlapping_facets(face *f1, face *f2, REAL dihedang)
7121 {
7122  point pa, pb, pc, pd;
7123 
7124  pa = sorg(*f1);
7125  pb = sdest(*f1);
7126  pc = sapex(*f1);
7127  pd = sapex(*f2);
7128 
7129  if (pc != pd) {
7130  printf("Found two %s self-intersecting facets.\n",
7131  dihedang > 0 ? "nearly" : "exactly");
7132  printf(" 1st: [%d, %d, %d] #%d\n",
7133  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
7134  printf(" 2nd: [%d, %d, %d] #%d\n",
7135  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
7136  if (dihedang > 0) {
7137  printf("The dihedral angle between them is %g degree.\n",
7138  dihedang / PI * 180.0);
7139  printf("Hint: You may use -p/# to decrease the dihedral angle");
7140  printf(" tolerance %g (degree).\n", b->facet_overlap_ang_tol);
7141  }
7142  } else {
7143  if (shellmark(*f1) != shellmark(*f2)) {
7144  // Two identical faces from two different facet.
7145  printf("Found two overlapping facets.\n");
7146  } else {
7147  printf("Found two duplicated facets.\n");
7148  }
7149  printf(" 1st: [%d, %d, %d] #%d\n",
7150  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
7151  printf(" 2nd: [%d, %d, %d] #%d\n",
7152  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
7153  }
7154 
7155  // Return the information
7156  sevent.e_type = 6;
7157  sevent.f_marker1 = shellmark(*f1);
7158  sevent.f_vertices1[0] = pointmark(pa);
7159  sevent.f_vertices1[1] = pointmark(pb);
7160  sevent.f_vertices1[2] = pointmark(pc);
7161  sevent.f_marker2 = shellmark(*f2);
7162  sevent.f_vertices2[0] = pointmark(pa);
7163  sevent.f_vertices2[1] = pointmark(pb);
7164  sevent.f_vertices2[2] = pointmark(pd);
7165 
7166  terminatetetgen(this, 3);
7167 }
7168 
7170 // //
7171 // report_selfint_edge() Report a self-intersection at an edge. //
7172 // //
7173 // The edge 'e1'->'e2' and the tetrahedron 'itet' intersect. 'dir' indicates //
7174 // that the edge intersects the tet at its origin vertex (ACROSSVERTEX), or //
7175 // its current face (ACROSSFACE), or its current edge (ACROSSEDGE). //
7176 // If 'iedge' is not NULL, it is either a segment or a subface that contains //
7177 // the edge 'e1'->'e2'. It is used to report the geometry entity. //
7178 // //
7179 // Since it is a self-intersection, the vertex, edge or face of 'itet' that //
7180 // is intersecting with this edge must be an input vertex, a segment, or a //
7181 // subface, respectively. //
7182 // //
7184 
7185 int tetgenmesh::report_selfint_edge(point e1, point e2, face *iedge,
7186  triface* itet, enum interresult dir)
7187 {
7188  point forg = NULL, fdest = NULL, fapex = NULL;
7189  int etype = 0, geomtag = 0, facemark = 0;
7190 
7191  if (iedge != NULL) {
7192  if (iedge->sh[5] != NULL) {
7193  etype = 2; // A subface
7194  forg = e1;
7195  fdest = e2;
7196  fapex = sapex(*iedge);
7197  facemark = shellmark(*iedge);
7198  } else {
7199  etype = 1; // A segment
7200  forg = farsorg(*iedge);
7201  fdest = farsdest(*iedge);
7202  // Get a facet containing this segment.
7203  face parentsh;
7204  spivot(*iedge, parentsh);
7205  if (parentsh.sh != NULL) {
7206  facemark = shellmark(parentsh);
7207  }
7208  }
7209  geomtag = shellmark(*iedge);
7210  }
7211 
7212  if (dir == SHAREEDGE) {
7213  // Two edges (segments) are coincide.
7214  face colseg;
7215  tsspivot1(*itet, colseg);
7216  if (etype == 1) {
7217  if (colseg.sh != iedge->sh) {
7218  face parentsh;
7219  spivot(colseg, parentsh);
7220  printf("PLC Error: Two segments are overlapping.\n");
7221  printf(" Segment 1: [%d, %d] #%d (%d)\n", pointmark(sorg(colseg)),
7222  pointmark(sdest(colseg)), shellmark(colseg),
7223  parentsh.sh ? shellmark(parentsh) : 0);
7224  printf(" Segment 2: [%d, %d] #%d (%d)\n", pointmark(forg),
7225  pointmark(fdest), geomtag, facemark);
7226  sevent.e_type = 4;
7227  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
7228  sevent.s_marker1 = shellmark(colseg);
7229  sevent.f_vertices1[0] = pointmark( sorg(colseg));
7230  sevent.f_vertices1[1] = pointmark(sdest(colseg));
7231  sevent.f_vertices1[2] = 0;
7232  sevent.f_marker2 = facemark;
7233  sevent.s_marker2 = geomtag;
7234  sevent.f_vertices2[0] = pointmark(forg);
7235  sevent.f_vertices2[1] = pointmark(fdest);
7236  sevent.f_vertices2[2] = 0;
7237  } else {
7238  // Two identical segments. Why report it?
7239  terminatetetgen(this, 2);
7240  }
7241  } else if (etype == 2) {
7242  printf("PLC Error: A segment lies in a facet.\n");
7243  printf(" Segment: [%d, %d] #%d\n", pointmark(sorg(colseg)),
7244  pointmark(sdest(colseg)), shellmark(colseg));
7245  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg),
7246  pointmark(fdest), pointmark(fapex), geomtag);
7247  sevent.e_type = 5;
7248  sevent.f_marker1 = 0;
7249  sevent.s_marker1 = shellmark(colseg);
7250  sevent.f_vertices1[0] = pointmark( sorg(colseg));
7251  sevent.f_vertices1[1] = pointmark(sdest(colseg));
7252  sevent.f_vertices1[2] = 0;
7253  sevent.f_marker2 = geomtag;
7254  sevent.s_marker2 = 0;
7255  sevent.f_vertices2[0] = pointmark(forg);
7256  sevent.f_vertices2[1] = pointmark(fdest);
7257  sevent.f_vertices2[2] = pointmark(fapex);
7258  }
7259  } else if (dir == SHAREFACE) {
7260  // Two triangles (subfaces) are coincide.
7261  face colface;
7262  tspivot(*itet, colface);
7263  if (etype == 2) {
7264  if (colface.sh != iedge->sh) {
7265  printf("PLC Error: Two facets are overlapping.\n");
7266  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(forg),
7267  pointmark(fdest), pointmark(fapex), geomtag);
7268  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(sorg(colface)),
7269  pointmark(sdest(colface)), pointmark(sapex(colface)),
7270  shellmark(colface));
7271  sevent.e_type = 6;
7272  sevent.f_marker1 = geomtag;
7273  sevent.s_marker1 = 0;
7274  sevent.f_vertices1[0] = pointmark(forg);
7275  sevent.f_vertices1[1] = pointmark(fdest);
7276  sevent.f_vertices1[2] = pointmark(fapex);
7277  sevent.f_marker2 = shellmark(colface);
7278  sevent.s_marker2 = 0;
7279  sevent.f_vertices2[0] = pointmark(sorg(colface));
7280  sevent.f_vertices2[1] = pointmark(sdest(colface));
7281  sevent.f_vertices2[2] = pointmark(sapex(colface));
7282  } else {
7283  // Two identical subfaces. Why report it?
7284  terminatetetgen(this, 2);
7285  }
7286  } else {
7287  terminatetetgen(this, 2);
7288  }
7289  } else if (dir == ACROSSVERT) {
7290  point pp = dest(*itet);
7291  if ((pointtype(pp) == RIDGEVERTEX) || (pointtype(pp) == FACETVERTEX)
7292  || (pointtype(pp) == VOLVERTEX)) {
7293  if (etype == 1) {
7294  printf("PLC Error: A vertex lies in a segment.\n");
7295  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
7296  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(forg),
7297  pointmark(fdest), geomtag, facemark);
7298  sevent.e_type = 7;
7299  sevent.f_marker1 = 0;
7300  sevent.s_marker1 = 0;
7301  sevent.f_vertices1[0] = pointmark(pp);
7302  sevent.f_vertices1[1] = 0;
7303  sevent.f_vertices1[2] = 0;
7304  sevent.f_marker2 = facemark;
7305  sevent.s_marker2 = geomtag;
7306  sevent.f_vertices2[0] = pointmark(forg);
7307  sevent.f_vertices2[1] = pointmark(fdest);
7308  sevent.f_vertices2[2] = 0;
7309  sevent.int_point[0] = pp[0];
7310  sevent.int_point[1] = pp[1];
7311  sevent.int_point[2] = pp[2];
7312  } else if (etype == 2) {
7313  printf("PLC Error: A vertex lies in a facet.\n");
7314  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
7315  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg), pointmark(fdest),
7316  pointmark(fapex), geomtag);
7317  sevent.e_type = 8;
7318  sevent.f_marker1 = 0;
7319  sevent.s_marker1 = 0;
7320  sevent.f_vertices1[0] = pointmark(pp);
7321  sevent.f_vertices1[1] = 0;
7322  sevent.f_vertices1[2] = 0;
7323  sevent.f_marker2 = geomtag;
7324  sevent.s_marker2 = 0;
7325  sevent.f_vertices2[0] = pointmark(forg);
7326  sevent.f_vertices2[1] = pointmark(fdest);
7327  sevent.f_vertices2[2] = pointmark(fapex);
7328  sevent.int_point[0] = pp[0];
7329  sevent.int_point[1] = pp[1];
7330  sevent.int_point[2] = pp[2];
7331  }
7332  } else if (pointtype(pp) == FREESEGVERTEX) {
7333  face parentseg, parentsh;
7334  sdecode(point2sh(pp), parentseg);
7335  spivot(parentseg, parentsh);
7336  if (parentseg.sh != NULL) {
7337  point p1 = farsorg(parentseg);
7338  point p2 = farsdest(parentseg);
7339  if (etype == 1) {
7340  printf("PLC Error: Two segments intersect at point (%g,%g,%g).\n",
7341  pp[0], pp[1], pp[2]);
7342  printf(" Segment 1: [%d, %d], #%d (%d)\n", pointmark(forg),
7343  pointmark(fdest), geomtag, facemark);
7344  printf(" Segment 2: [%d, %d], #%d (%d)\n", pointmark(p1),
7345  pointmark(p2), shellmark(parentseg),
7346  parentsh.sh ? shellmark(parentsh) : 0);
7347  sevent.e_type = 1;
7348  sevent.f_marker1 = facemark;
7349  sevent.s_marker1 = geomtag;
7350  sevent.f_vertices1[0] = pointmark(forg);
7351  sevent.f_vertices1[1] = pointmark(fdest);
7352  sevent.f_vertices1[2] = 0;
7353  sevent.f_marker2 = (parentsh.sh ? shellmark(parentsh) : 0);
7354  sevent.s_marker2 = shellmark(parentseg);
7355  sevent.f_vertices2[0] = pointmark(p1);
7356  sevent.f_vertices2[1] = pointmark(p2);
7357  sevent.f_vertices2[2] = 0;
7358  sevent.int_point[0] = pp[0];
7359  sevent.int_point[1] = pp[1];
7360  sevent.int_point[2] = pp[2];
7361  } else if (etype == 2) {
7362  printf("PLC Error: A segment and a facet intersect at point");
7363  printf(" (%g,%g,%g).\n", pp[0], pp[1], pp[2]);
7364  printf(" Segment: [%d, %d], #%d (%d)\n", pointmark(p1),
7365  pointmark(p2), shellmark(parentseg),
7366  parentsh.sh ? shellmark(parentsh) : 0);
7367  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg),
7368  pointmark(fdest), pointmark(fapex), geomtag);
7369  sevent.e_type = 2;
7370  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
7371  sevent.s_marker1 = shellmark(parentseg);
7372  sevent.f_vertices1[0] = pointmark(p1);
7373  sevent.f_vertices1[1] = pointmark(p2);
7374  sevent.f_vertices1[2] = 0;
7375  sevent.f_marker2 = geomtag;
7376  sevent.s_marker2 = 0;
7377  sevent.f_vertices2[0] = pointmark(forg);
7378  sevent.f_vertices2[1] = pointmark(fdest);
7379  sevent.f_vertices2[2] = pointmark(fapex);
7380  sevent.int_point[0] = pp[0];
7381  sevent.int_point[1] = pp[1];
7382  sevent.int_point[2] = pp[2];
7383  }
7384  } else {
7385  terminatetetgen(this, 2); // Report a bug.
7386  }
7387  } else if (pointtype(pp) == FREEFACETVERTEX) {
7388  face parentsh;
7389  sdecode(point2sh(pp), parentsh);
7390  if (parentsh.sh != NULL) {
7391  point p1 = sorg(parentsh);
7392  point p2 = sdest(parentsh);
7393  point p3 = sapex(parentsh);
7394  if (etype == 1) {
7395  printf("PLC Error: A segment and a facet intersect at point");
7396  printf(" (%g,%g,%g).\n", pp[0], pp[1], pp[2]);
7397  printf(" Segment : [%d, %d], #%d (%d)\n", pointmark(forg),
7398  pointmark(fdest), geomtag, facemark);
7399  printf(" Facet : [%d, %d, %d] #%d.\n", pointmark(p1),
7400  pointmark(p2), pointmark(p3), shellmark(parentsh));
7401  sevent.e_type = 2;
7402  sevent.f_marker1 = facemark;
7403  sevent.s_marker1 = geomtag;
7404  sevent.f_vertices1[0] = pointmark(forg);
7405  sevent.f_vertices1[1] = pointmark(fdest);
7406  sevent.f_vertices1[2] = 0;
7407  sevent.f_marker2 = shellmark(parentsh);
7408  sevent.s_marker2 = 0;
7409  sevent.f_vertices2[0] = pointmark(p1);
7410  sevent.f_vertices2[1] = pointmark(p2);
7411  sevent.f_vertices2[2] = pointmark(p3);
7412  sevent.int_point[0] = pp[0];
7413  sevent.int_point[1] = pp[1];
7414  sevent.int_point[2] = pp[2];
7415  } else if (etype == 2) {
7416  printf("PLC Error: Two facets intersect at point (%g,%g,%g).\n",
7417  pp[0], pp[1], pp[2]);
7418  printf(" Facet 1: [%d, %d, %d] #%d.\n", pointmark(forg),
7419  pointmark(fdest), pointmark(fapex), geomtag);
7420  printf(" Facet 2: [%d, %d, %d] #%d.\n", pointmark(p1),
7421  pointmark(p2), pointmark(p3), shellmark(parentsh));
7422  sevent.e_type = 3;
7423  sevent.f_marker1 = geomtag;
7424  sevent.s_marker1 = 0;
7425  sevent.f_vertices1[0] = pointmark(forg);
7426  sevent.f_vertices1[1] = pointmark(fdest);
7427  sevent.f_vertices1[2] = pointmark(fapex);
7428  sevent.f_marker2 = shellmark(parentsh);
7429  sevent.s_marker2 = 0;
7430  sevent.f_vertices2[0] = pointmark(p1);
7431  sevent.f_vertices2[1] = pointmark(p2);
7432  sevent.f_vertices2[2] = pointmark(p3);
7433  sevent.int_point[0] = pp[0];
7434  sevent.int_point[1] = pp[1];
7435  sevent.int_point[2] = pp[2];
7436  }
7437  } else {
7438  terminatetetgen(this, 2); // Report a bug.
7439  }
7440  } else if (pointtype(pp) == FREEVOLVERTEX) {
7441  // This is not a PLC error.
7442  // We should shift the vertex.
7443  // not down yet.
7444  terminatetetgen(this, 2); // Report a bug.
7445  } else {
7446  terminatetetgen(this, 2); // Report a bug.
7447  }
7448  terminatetetgen(this, 3);
7449  } else if (dir == ACROSSEDGE) {
7450  if (issubseg(*itet)) {
7451  face checkseg;
7452  tsspivot1(*itet, checkseg);
7453  face parentsh;
7454  spivot(checkseg, parentsh);
7455  // Calulcate the intersecting point.
7456  point p1 = sorg(checkseg);
7457  point p2 = sdest(checkseg);
7458  REAL P[3], Q[3], tp = 0, tq = 0;
7459  linelineint(e1, e2, p1, p2, P, Q, &tp, &tq);
7460  if (etype == 1) {
7461  printf("PLC Error: Two segments intersect at point (%g,%g,%g).\n",
7462  P[0], P[1], P[2]);
7463  printf(" Segment 1: [%d, %d] #%d (%d)\n", pointmark(forg),
7464  pointmark(fdest), geomtag, facemark);
7465  printf(" Segment 2: [%d, %d] #%d (%d)\n", pointmark(p1),
7466  pointmark(p2), shellmark(checkseg),
7467  parentsh.sh ? shellmark(parentsh) : 0);
7468  sevent.e_type = 1;
7469  sevent.f_marker1 = facemark;
7470  sevent.s_marker1 = geomtag;
7471  sevent.f_vertices1[0] = pointmark(forg);
7472  sevent.f_vertices1[1] = pointmark(fdest);
7473  sevent.f_vertices1[2] = 0;
7474  sevent.f_marker2 = (parentsh.sh ? shellmark(parentsh) : 0);
7475  sevent.s_marker2 = shellmark(checkseg);
7476  sevent.f_vertices2[0] = pointmark(p1);
7477  sevent.f_vertices2[1] = pointmark(p2);
7478  sevent.f_vertices2[2] = 0;
7479  sevent.int_point[0] = P[0];
7480  sevent.int_point[1] = P[1];
7481  sevent.int_point[2] = P[2];
7482  } else if (etype == 2) {
7483  printf("PLC Error: A segment and a facet intersect at point");
7484  printf(" (%g,%g,%g).\n", P[0], P[1], P[2]);
7485  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(p1),
7486  pointmark(p2), shellmark(checkseg),
7487  parentsh.sh ? shellmark(parentsh) : 0);
7488  printf(" Facet: [%d, %d, %d] #%d.\n", pointmark(forg),
7489  pointmark(fdest), pointmark(fapex), geomtag);
7490  sevent.e_type = 2;
7491  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
7492  sevent.s_marker1 = shellmark(checkseg);
7493  sevent.f_vertices1[0] = pointmark(p1);
7494  sevent.f_vertices1[1] = pointmark(p2);
7495  sevent.f_vertices1[2] = 0;
7496  sevent.f_marker2 = geomtag;
7497  sevent.s_marker2 = 0;
7498  sevent.f_vertices2[0] = pointmark(forg);
7499  sevent.f_vertices2[1] = pointmark(fdest);
7500  sevent.f_vertices2[2] = pointmark(fapex);
7501  sevent.int_point[0] = P[0];
7502  sevent.int_point[1] = P[1];
7503  sevent.int_point[2] = P[2];
7504  }
7505  terminatetetgen(this, 3);
7506  }
7507  } else if (dir == ACROSSFACE) {
7508  if (issubface(*itet)) {
7509  face checksh;
7510  tspivot(*itet, checksh);
7511  point p1 = sorg(checksh);
7512  point p2 = sdest(checksh);
7513  point p3 = sapex(checksh);
7514  REAL ip[3], u = 0;
7515  planelineint(p1, p2, p3, e1, e2, ip, &u);
7516  if (etype == 1) {
7517  printf("PLC Error: A segment and a facet intersect at point");
7518  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
7519  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(forg),
7520  pointmark(fdest), geomtag, facemark);
7521  printf(" Facet: [%d, %d, %d] #%d.\n", pointmark(p1),
7522  pointmark(p2), pointmark(p3), shellmark(checksh));
7523  sevent.e_type = 2;
7524  sevent.f_marker1 = facemark;
7525  sevent.s_marker1 = geomtag;
7526  sevent.f_vertices1[0] = pointmark(forg);
7527  sevent.f_vertices1[1] = pointmark(fdest);
7528  sevent.f_vertices1[2] = 0;
7529  sevent.f_marker2 = shellmark(checksh);
7530  sevent.s_marker2 = 0;
7531  sevent.f_vertices2[0] = pointmark(p1);
7532  sevent.f_vertices2[1] = pointmark(p2);
7533  sevent.f_vertices2[2] = pointmark(p3);
7534  sevent.int_point[0] = ip[0];
7535  sevent.int_point[1] = ip[1];
7536  sevent.int_point[2] = ip[2];
7537  } else if (etype == 2) {
7538  printf("PLC Error: Two facets intersect at point (%g,%g,%g).\n",
7539  ip[0], ip[1], ip[2]);
7540  printf(" Facet 1: [%d, %d, %d] #%d.\n", pointmark(forg),
7541  pointmark(fdest), pointmark(fapex), geomtag);
7542  printf(" Facet 2: [%d, %d, %d] #%d.\n", pointmark(p1),
7543  pointmark(p2), pointmark(p3), shellmark(checksh));
7544  sevent.e_type = 3;
7545  sevent.f_marker1 = geomtag;
7546  sevent.s_marker1 = 0;
7547  sevent.f_vertices1[0] = pointmark(forg);
7548  sevent.f_vertices1[1] = pointmark(fdest);
7549  sevent.f_vertices1[2] = pointmark(fapex);
7550  sevent.f_marker2 = shellmark(checksh);
7551  sevent.s_marker2 = 0;
7552  sevent.f_vertices2[0] = pointmark(p1);
7553  sevent.f_vertices2[1] = pointmark(p2);
7554  sevent.f_vertices2[2] = pointmark(p3);
7555  sevent.int_point[0] = ip[0];
7556  sevent.int_point[1] = ip[1];
7557  sevent.int_point[2] = ip[2];
7558  }
7559  terminatetetgen(this, 3);
7560  }
7561  } else {
7562  // An unknown 'dir'.
7563  terminatetetgen(this, 2);
7564  }
7565  return 0;
7566 }
7567 
7569 // //
7570 // report_selfint_face() Report a self-intersection at a facet. //
7571 // //
7572 // The triangle with vertices 'p1', 'p2', and 'p3' intersects with the edge //
7573 // of the tetrahedra 'iedge'. The intersection type is reported by 'intflag',//
7574 // 'types', and 'poss'. //
7575 // //
7576 // This routine ASSUMES (1) the triangle (p1,p2,p3) must belong to a facet, //
7577 // 'sface' is a subface of the same facet; and (2) 'iedge' must be either a //
7578 // segment or an edge of another facet. //
7579 // //
7581 
7582 int tetgenmesh::report_selfint_face(point p1, point p2, point p3, face* sface,
7583  triface* iedge, int intflag, int* types, int* poss)
7584 {
7585  face iface;
7586  point e1 = NULL, e2 = NULL, e3 = NULL;
7587  int etype = 0, geomtag = 0, facemark = 0;
7588 
7589  geomtag = shellmark(*sface);
7590 
7591  if (issubface(*iedge)) {
7592  tspivot(*iedge, iface);
7593  e1 = sorg(iface);
7594  e2 = sdest(iface);
7595  e3 = sapex(iface);
7596  etype = 2;
7597  facemark = geomtag;
7598  } else if (issubseg(*iedge)) {
7599  tsspivot1(*iedge, iface);
7600  e1 = farsorg(iface);
7601  e2 = farsdest(iface);
7602  etype = 1;
7603  face parentsh;
7604  spivot(iface, parentsh);
7605  facemark = shellmark(parentsh);
7606  } else {
7607  terminatetetgen(this, 2);
7608  }
7609 
7610  if (intflag == 2) {
7611  // The triangle and the edge intersect only at one point.
7612  REAL ip[3], u = 0;
7613  planelineint(p1, p2, p3, e1, e2, ip, &u);
7614  if ((types[0] == (int) ACROSSFACE) ||
7615  (types[0] == (int) ACROSSEDGE)) {
7616  // The triangle and the edge intersect in their interiors.
7617  if (etype == 1) {
7618  printf("PLC Error: A segment and a facet intersect at point");
7619  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
7620  printf(" Segment: [%d,%d] #%d (%d)\n", pointmark(e1), pointmark(e2),
7621  shellmark(iface), facemark);
7622  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
7623  pointmark(p2), pointmark(p3), geomtag);
7624  sevent.e_type = 2;
7625  sevent.f_marker1 = facemark;
7626  sevent.s_marker1 = shellmark(iface);
7627  sevent.f_vertices1[0] = pointmark(e1);
7628  sevent.f_vertices1[1] = pointmark(e2);
7629  sevent.f_vertices1[2] = 0;
7630  sevent.f_marker2 = geomtag;
7631  sevent.s_marker2 = 0;
7632  sevent.f_vertices2[0] = pointmark(p1);
7633  sevent.f_vertices2[1] = pointmark(p2);
7634  sevent.f_vertices2[2] = pointmark(p3);
7635  sevent.int_point[0] = ip[0];
7636  sevent.int_point[1] = ip[1];
7637  sevent.int_point[2] = ip[2];
7638  } else {
7639  printf("PLC Error: Two facets intersect at point");
7640  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
7641  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(e1), pointmark(e2),
7642  pointmark(sorg(iface)), shellmark(iface));
7643  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(p1),
7644  pointmark(p2), pointmark(p3), geomtag);
7645  sevent.e_type = 3;
7646  sevent.f_marker1 = shellmark(iface);
7647  sevent.s_marker1 = 0;
7648  sevent.f_vertices1[0] = pointmark(e1);
7649  sevent.f_vertices1[1] = pointmark(e2);
7650  sevent.f_vertices1[2] = pointmark(sorg(iface));
7651  sevent.f_marker2 = geomtag;
7652  sevent.s_marker2 = 0;
7653  sevent.f_vertices2[0] = pointmark(p1);
7654  sevent.f_vertices2[1] = pointmark(p2);
7655  sevent.f_vertices2[2] = pointmark(p3);
7656  sevent.int_point[0] = ip[0];
7657  sevent.int_point[1] = ip[1];
7658  sevent.int_point[2] = ip[2];
7659  }
7660  } else if (types[0] == (int) ACROSSVERT) {
7661  // A vertex of the triangle and the edge intersect.
7662  point crosspt = NULL;
7663  if (poss[0] == 0) {
7664  crosspt = p1;
7665  } else if (poss[0] == 1) {
7666  crosspt = p2;
7667  } else if (poss[0] == 2) {
7668  crosspt = p3;
7669  } else {
7670  terminatetetgen(this, 2);
7671  }
7672  if (!issteinerpoint(crosspt)) {
7673  if (etype == 1) {
7674  printf("PLC Error: A vertex and a segment intersect at (%g,%g,%g)\n",
7675  crosspt[0], crosspt[1], crosspt[2]);
7676  printf(" Vertex: #%d\n", pointmark(crosspt));
7677  printf(" Segment: [%d,%d] #%d (%d)\n", pointmark(e1), pointmark(e2),
7678  shellmark(iface), facemark);
7679  sevent.e_type = 7;
7680  sevent.f_marker1 = 0;
7681  sevent.s_marker1 = 0;
7682  sevent.f_vertices1[0] = pointmark(crosspt);
7683  sevent.f_vertices1[1] = 0;
7684  sevent.f_vertices1[2] = 0;
7685  sevent.f_marker2 = facemark;
7686  sevent.s_marker2 = shellmark(iface);
7687  sevent.f_vertices2[0] = pointmark(e1);
7688  sevent.f_vertices2[1] = pointmark(e2);
7689  sevent.f_vertices2[2] = 0;
7690  sevent.int_point[0] = crosspt[0];
7691  sevent.int_point[1] = crosspt[1];
7692  sevent.int_point[2] = crosspt[2];
7693  } else {
7694  printf("PLC Error: A vertex and a facet intersect at (%g,%g,%g)\n",
7695  crosspt[0], crosspt[1], crosspt[2]);
7696  printf(" Vertex: #%d\n", pointmark(crosspt));
7697  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
7698  pointmark(p2), pointmark(p3), geomtag);
7699  sevent.e_type = 8;
7700  sevent.f_marker1 = 0;
7701  sevent.s_marker1 = 0;
7702  sevent.f_vertices1[0] = pointmark(crosspt);
7703  sevent.f_vertices1[1] = 0;
7704  sevent.f_vertices1[2] = 0;
7705  sevent.f_marker2 = geomtag;
7706  sevent.s_marker2 = 0;
7707  sevent.f_vertices2[0] = pointmark(p1);
7708  sevent.f_vertices2[1] = pointmark(p2);
7709  sevent.f_vertices2[2] = pointmark(p3);
7710  sevent.int_point[0] = crosspt[0];
7711  sevent.int_point[1] = crosspt[1];
7712  sevent.int_point[2] = crosspt[2];
7713  }
7714  } else {
7715  // It is a Steiner point. To be processed.
7716  terminatetetgen(this, 2);
7717  }
7718  } else if ((types[0] == (int) TOUCHFACE) ||
7719  (types[0] == (int) TOUCHEDGE)) {
7720  // The triangle and a vertex of the edge intersect.
7721  point touchpt = NULL;
7722  if (poss[1] == 0) {
7723  touchpt = org(*iedge);
7724  } else if (poss[1] == 1) {
7725  touchpt = dest(*iedge);
7726  } else {
7727  terminatetetgen(this, 2);
7728  }
7729  if (!issteinerpoint(touchpt)) {
7730  printf("PLC Error: A vertex and a facet intersect at (%g,%g,%g)\n",
7731  touchpt[0], touchpt[1], touchpt[2]);
7732  printf(" Vertex: #%d\n", pointmark(touchpt));
7733  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
7734  pointmark(p2), pointmark(p3), geomtag);
7735  sevent.e_type = 8;
7736  sevent.f_marker1 = 0;
7737  sevent.s_marker1 = 0;
7738  sevent.f_vertices1[0] = pointmark(touchpt);
7739  sevent.f_vertices1[1] = 0;
7740  sevent.f_vertices1[2] = 0;
7741  sevent.f_marker2 = geomtag;
7742  sevent.s_marker2 = 0;
7743  sevent.f_vertices2[0] = pointmark(p1);
7744  sevent.f_vertices2[1] = pointmark(p2);
7745  sevent.f_vertices2[2] = pointmark(p3);
7746  sevent.int_point[0] = touchpt[0];
7747  sevent.int_point[1] = touchpt[1];
7748  sevent.int_point[2] = touchpt[2];
7749  } else {
7750  // It is a Steiner point. To be processed.
7751  terminatetetgen(this, 2);
7752  }
7753  } else if (types[0] == (int) SHAREVERT) {
7754  terminatetetgen(this, 2);
7755  } else {
7756  terminatetetgen(this, 2);
7757  }
7758  } else if (intflag == 4) {
7759  if (types[0] == (int) SHAREFACE) {
7760  printf("PLC Error: Two facets are overlapping.\n");
7761  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(e1),
7762  pointmark(e2), pointmark(e3), facemark);
7763  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(p1),
7764  pointmark(p2), pointmark(p3), geomtag);
7765  sevent.e_type = 6;
7766  sevent.f_marker1 = facemark;
7767  sevent.s_marker1 = 0;
7768  sevent.f_vertices1[0] = pointmark(e1);
7769  sevent.f_vertices1[1] = pointmark(e2);
7770  sevent.f_vertices1[2] = pointmark(e3);
7771  sevent.f_marker2 = geomtag;
7772  sevent.s_marker2 = 0;
7773  sevent.f_vertices2[0] = pointmark(p1);
7774  sevent.f_vertices2[1] = pointmark(p2);
7775  sevent.f_vertices2[2] = pointmark(p3);
7776  } else {
7777  terminatetetgen(this, 2);
7778  }
7779  } else {
7780  terminatetetgen(this, 2);
7781  }
7782 
7783  terminatetetgen(this, 3);
7784  return 0;
7785 }
7786 
7790 
7794 
7796 // //
7797 // flip23() Perform a 2-to-3 flip (face-to-edge flip). //
7798 // //
7799 // 'fliptets' is an array of three tets (handles), where the [0] and [1] are //
7800 // [a,b,c,d] and [b,a,c,e]. The three new tets: [e,d,a,b], [e,d,b,c], and //
7801 // [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'. As a result, //
7802 // The face [a,b,c] is removed, and the edge [d,e] is created. //
7803 // //
7804 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
7805 // the five vertices may be 'dummypoint'. There are two canonical cases: //
7806 // (1) d is 'dummypoint', then all three new tets are hull tets. If e is //
7807 // 'dummypoint', we reconfigure e to d, i.e., turn it up-side down. //
7808 // (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are //
7809 // hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
7810 // rotate the three input tets counterclockwisely (right-hand rule) //
7811 // until a or b is in c's position. //
7812 // //
7813 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
7814 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
7815 // after the insertion of a new point. It is assumed that 'd' is the new //
7816 // point. IN this case, only link faces of 'd' are queued. //
7817 // //
7819 
7820 void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
7821 {
7822  triface topcastets[3], botcastets[3];
7823  triface newface, casface;
7824  point pa, pb, pc, pd, pe;
7825  REAL attrib, volume;
7826  int dummyflag = 0; // range = {-1, 0, 1, 2}.
7827  int i;
7828 
7829  if (hullflag > 0) {
7830  // Check if e is dummypoint.
7831  if (oppo(fliptets[1]) == dummypoint) {
7832  // Swap the two old tets.
7833  newface = fliptets[0];
7834  fliptets[0] = fliptets[1];
7835  fliptets[1] = newface;
7836  dummyflag = -1; // d is dummypoint.
7837  } else {
7838  // Check if either a or b is dummypoint.
7839  if (org(fliptets[0]) == dummypoint) {
7840  dummyflag = 1; // a is dummypoint.
7841  enextself(fliptets[0]);
7842  eprevself(fliptets[1]);
7843  } else if (dest(fliptets[0]) == dummypoint) {
7844  dummyflag = 2; // b is dummypoint.
7845  eprevself(fliptets[0]);
7846  enextself(fliptets[1]);
7847  } else {
7848  dummyflag = 0; // either c or d may be dummypoint.
7849  }
7850  }
7851  }
7852 
7853  pa = org(fliptets[0]);
7854  pb = dest(fliptets[0]);
7855  pc = apex(fliptets[0]);
7856  pd = oppo(fliptets[0]);
7857  pe = oppo(fliptets[1]);
7858 
7859  flip23count++;
7860 
7861  // Get the outer boundary faces.
7862  for (i = 0; i < 3; i++) {
7863  fnext(fliptets[0], topcastets[i]);
7864  enextself(fliptets[0]);
7865  }
7866  for (i = 0; i < 3; i++) {
7867  fnext(fliptets[1], botcastets[i]);
7868  eprevself(fliptets[1]);
7869  }
7870 
7871  // Re-use fliptets[0] and fliptets[1].
7872  fliptets[0].ver = 11;
7873  fliptets[1].ver = 11;
7874  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7875  setelemmarker(fliptets[1].tet, 0);
7876  // NOTE: the element attributes and volume constraint remain unchanged.
7877  if (checksubsegflag) {
7878  // Dealloc the space to subsegments.
7879  if (fliptets[0].tet[8] != NULL) {
7880  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7881  fliptets[0].tet[8] = NULL;
7882  }
7883  if (fliptets[1].tet[8] != NULL) {
7884  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7885  fliptets[1].tet[8] = NULL;
7886  }
7887  }
7888  if (checksubfaceflag) {
7889  // Dealloc the space to subfaces.
7890  if (fliptets[0].tet[9] != NULL) {
7891  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7892  fliptets[0].tet[9] = NULL;
7893  }
7894  if (fliptets[1].tet[9] != NULL) {
7895  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7896  fliptets[1].tet[9] = NULL;
7897  }
7898  }
7899  // Create a new tet.
7900  maketetrahedron(&(fliptets[2]));
7901  // The new tet have the same attributes from the old tet.
7902  for (i = 0; i < numelemattrib; i++) {
7903  attrib = elemattribute(fliptets[0].tet, i);
7904  setelemattribute(fliptets[2].tet, i, attrib);
7905  }
7906  if (b->varvolume) {
7907  volume = volumebound(fliptets[0].tet);
7908  setvolumebound(fliptets[2].tet, volume);
7909  }
7910 
7911  if (hullflag > 0) {
7912  // Check if d is dummytet.
7913  if (pd != dummypoint) {
7914  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7915  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7916  // Check if c is dummypoint.
7917  if (pc != dummypoint) {
7918  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7919  } else {
7920  setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
7921  esymself(fliptets[2]); // [e,d,c,a] *
7922  }
7923  // The hullsize does not change.
7924  } else {
7925  // d is dummypoint.
7926  setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
7927  setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
7928  setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
7929  // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
7930  for (i = 0; i < 3; i++) {
7931  eprevesymself(fliptets[i]);
7932  enextself(fliptets[i]);
7933  }
7934  // We deleted one hull tet, and created three hull tets.
7935  hullsize += 2;
7936  }
7937  } else {
7938  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7939  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7940  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7941  }
7942 
7943  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7944  REAL volneg[2], volpos[3], vol_diff;
7945  if (pd != dummypoint) {
7946  if (pc != dummypoint) {
7947  volpos[0] = tetprismvol(pe, pd, pa, pb);
7948  volpos[1] = tetprismvol(pe, pd, pb, pc);
7949  volpos[2] = tetprismvol(pe, pd, pc, pa);
7950  volneg[0] = tetprismvol(pa, pb, pc, pd);
7951  volneg[1] = tetprismvol(pb, pa, pc, pe);
7952  } else { // pc == dummypoint
7953  volpos[0] = tetprismvol(pe, pd, pa, pb);
7954  volpos[1] = 0.;
7955  volpos[2] = 0.;
7956  volneg[0] = 0.;
7957  volneg[1] = 0.;
7958  }
7959  } else { // pd == dummypoint.
7960  volpos[0] = 0.;
7961  volpos[1] = 0.;
7962  volpos[2] = 0.;
7963  volneg[0] = 0.;
7964  volneg[1] = tetprismvol(pb, pa, pc, pe);
7965  }
7966  vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
7967  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7968  }
7969 
7970  // Bond three new tets together.
7971  for (i = 0; i < 3; i++) {
7972  esym(fliptets[i], newface);
7973  bond(newface, fliptets[(i + 1) % 3]);
7974  }
7975  // Bond to top outer boundary faces (at [a,b,c,d]).
7976  for (i = 0; i < 3; i++) {
7977  eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
7978  bond(newface, topcastets[i]);
7979  }
7980  // Bond bottom outer boundary faces (at [b,a,c,e]).
7981  for (i = 0; i < 3; i++) {
7982  edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
7983  bond(newface, botcastets[i]);
7984  }
7985 
7986  if (checksubsegflag) {
7987  // Bond subsegments if there are.
7988  // Each new tet has 5 edges to be checked (except the edge [e,d]).
7989  face checkseg;
7990  // The middle three: [a,b], [b,c], [c,a].
7991  for (i = 0; i < 3; i++) {
7992  if (issubseg(topcastets[i])) {
7993  tsspivot1(topcastets[i], checkseg);
7994  eorgoppo(fliptets[i], newface);
7995  tssbond1(newface, checkseg);
7996  sstbond1(checkseg, newface);
7997  if (fc->chkencflag & 1) {
7998  enqueuesubface(badsubsegs, &checkseg);
7999  }
8000  }
8001  }
8002  // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
8003  for (i = 0; i < 3; i++) {
8004  eprev(topcastets[i], casface);
8005  if (issubseg(casface)) {
8006  tsspivot1(casface, checkseg);
8007  enext(fliptets[i], newface);
8008  tssbond1(newface, checkseg);
8009  sstbond1(checkseg, newface);
8010  esym(fliptets[(i + 2) % 3], newface);
8011  eprevself(newface);
8012  tssbond1(newface, checkseg);
8013  sstbond1(checkseg, newface);
8014  if (fc->chkencflag & 1) {
8015  enqueuesubface(badsubsegs, &checkseg);
8016  }
8017  }
8018  }
8019  // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
8020  for (i = 0; i < 3; i++) {
8021  enext(botcastets[i], casface);
8022  if (issubseg(casface)) {
8023  tsspivot1(casface, checkseg);
8024  eprev(fliptets[i], newface);
8025  tssbond1(newface, checkseg);
8026  sstbond1(checkseg, newface);
8027  esym(fliptets[(i + 2) % 3], newface);
8028  enextself(newface);
8029  tssbond1(newface, checkseg);
8030  sstbond1(checkseg, newface);
8031  if (fc->chkencflag & 1) {
8032  enqueuesubface(badsubsegs, &checkseg);
8033  }
8034  }
8035  }
8036  } // if (checksubsegflag)
8037 
8038  if (checksubfaceflag) {
8039  // Bond 6 subfaces if there are.
8040  face checksh;
8041  for (i = 0; i < 3; i++) {
8042  if (issubface(topcastets[i])) {
8043  tspivot(topcastets[i], checksh);
8044  eorgoppo(fliptets[i], newface);
8045  sesymself(checksh);
8046  tsbond(newface, checksh);
8047  if (fc->chkencflag & 2) {
8048  enqueuesubface(badsubfacs, &checksh);
8049  }
8050  }
8051  }
8052  for (i = 0; i < 3; i++) {
8053  if (issubface(botcastets[i])) {
8054  tspivot(botcastets[i], checksh);
8055  edestoppo(fliptets[i], newface);
8056  sesymself(checksh);
8057  tsbond(newface, checksh);
8058  if (fc->chkencflag & 2) {
8059  enqueuesubface(badsubfacs, &checksh);
8060  }
8061  }
8062  }
8063  } // if (checksubfaceflag)
8064 
8065  if (fc->chkencflag & 4) {
8066  // Put three new tets into check list.
8067  for (i = 0; i < 3; i++) {
8068  enqueuetetrahedron(&(fliptets[i]));
8069  }
8070  }
8071 
8072  // Update the point-to-tet map.
8073  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8074  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8075  setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
8076  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8077  setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
8078 
8079  if (hullflag > 0) {
8080  if (dummyflag != 0) {
8081  // Restore the original position of the points (for flipnm()).
8082  if (dummyflag == -1) {
8083  // Reverse the edge.
8084  for (i = 0; i < 3; i++) {
8085  esymself(fliptets[i]);
8086  }
8087  // Swap the last two new tets.
8088  newface = fliptets[1];
8089  fliptets[1] = fliptets[2];
8090  fliptets[2] = newface;
8091  } else {
8092  // either a or b were swapped.
8093  if (dummyflag == 1) {
8094  // a is dummypoint.
8095  newface = fliptets[0];
8096  fliptets[0] = fliptets[2];
8097  fliptets[2] = fliptets[1];
8098  fliptets[1] = newface;
8099  } else { // dummyflag == 2
8100  // b is dummypoint.
8101  newface = fliptets[0];
8102  fliptets[0] = fliptets[1];
8103  fliptets[1] = fliptets[2];
8104  fliptets[2] = newface;
8105  }
8106  }
8107  }
8108  }
8109 
8110  if (fc->enqflag > 0) {
8111  // Queue faces which may be locally non-Delaunay.
8112  for (i = 0; i < 3; i++) {
8113  eprevesym(fliptets[i], newface);
8114  flippush(flipstack, &newface);
8115  }
8116  if (fc->enqflag > 1) {
8117  for (i = 0; i < 3; i++) {
8118  enextesym(fliptets[i], newface);
8119  flippush(flipstack, &newface);
8120  }
8121  }
8122  }
8123 
8124  recenttet = fliptets[0];
8125 }
8126 
8128 // //
8129 // flip32() Perform a 3-to-2 flip (edge-to-face flip). //
8130 // //
8131 // 'fliptets' is an array of three tets (handles), which are [e,d,a,b], //
8132 // [e,d,b,c], and [e,d,c,a]. The two new tets: [a,b,c,d] and [b,a,c,e] are //
8133 // returned in [0] and [1] of 'fliptets'. As a result, the edge [e,d] is //
8134 // replaced by the face [a,b,c]. //
8135 // //
8136 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
8137 // the five vertices may be 'dummypoint'. There are two canonical cases: //
8138 // (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
8139 // we reconfigure e to d, i.e., turnover it. //
8140 // (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets. //
8141 // If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
8142 // three old tets counterclockwisely (right-hand rule) until a or b //
8143 // is in c's position. //
8144 // //
8145 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
8146 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
8147 // after the insertion of a new point. It is assumed that 'a' is the new //
8148 // point. In this case, only link faces of 'a' are queued. //
8149 // //
8150 // If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a //
8151 // segment. There may be two (interior) subfaces sharing at [e,d], which are //
8152 // [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c), //
8153 // or (c,a) In such case, a 2-to-2 flip is performed on these two subfaces //
8154 // and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted //
8155 // back into the tetrahedralization. //
8156 // //
8158 
8159 void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
8160 {
8161  triface topcastets[3], botcastets[3];
8162  triface newface, casface;
8163  face flipshs[3];
8164  face checkseg;
8165  point pa, pb, pc, pd, pe;
8166  REAL attrib, volume;
8167  int dummyflag = 0; // Rangle = {-1, 0, 1, 2}
8168  int spivot = -1, scount = 0; // for flip22()
8169  int t1ver;
8170  int i, j;
8171 
8172  if (hullflag > 0) {
8173  // Check if e is 'dummypoint'.
8174  if (org(fliptets[0]) == dummypoint) {
8175  // Reverse the edge.
8176  for (i = 0; i < 3; i++) {
8177  esymself(fliptets[i]);
8178  }
8179  // Swap the last two tets.
8180  newface = fliptets[1];
8181  fliptets[1] = fliptets[2];
8182  fliptets[2] = newface;
8183  dummyflag = -1; // e is dummypoint.
8184  } else {
8185  // Check if a or b is the 'dummypoint'.
8186  if (apex(fliptets[0]) == dummypoint) {
8187  dummyflag = 1; // a is dummypoint.
8188  newface = fliptets[0];
8189  fliptets[0] = fliptets[1];
8190  fliptets[1] = fliptets[2];
8191  fliptets[2] = newface;
8192  } else if (apex(fliptets[1]) == dummypoint) {
8193  dummyflag = 2; // b is dummypoint.
8194  newface = fliptets[0];
8195  fliptets[0] = fliptets[2];
8196  fliptets[2] = fliptets[1];
8197  fliptets[1] = newface;
8198  } else {
8199  dummyflag = 0; // either c or d may be dummypoint.
8200  }
8201  }
8202  }
8203 
8204  pa = apex(fliptets[0]);
8205  pb = apex(fliptets[1]);
8206  pc = apex(fliptets[2]);
8207  pd = dest(fliptets[0]);
8208  pe = org(fliptets[0]);
8209 
8210  flip32count++;
8211 
8212  // Get the outer boundary faces.
8213  for (i = 0; i < 3; i++) {
8214  eorgoppo(fliptets[i], casface);
8215  fsym(casface, topcastets[i]);
8216  }
8217  for (i = 0; i < 3; i++) {
8218  edestoppo(fliptets[i], casface);
8219  fsym(casface, botcastets[i]);
8220  }
8221 
8222  if (checksubfaceflag) {
8223  // Check if there are interior subfaces at the edge [e,d].
8224  for (i = 0; i < 3; i++) {
8225  tspivot(fliptets[i], flipshs[i]);
8226  if (flipshs[i].sh != NULL) {
8227  // Found an interior subface.
8228  stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
8229  scount++;
8230  } else {
8231  spivot = i;
8232  }
8233  }
8234  }
8235 
8236  // Re-use fliptets[0] and fliptets[1].
8237  fliptets[0].ver = 11;
8238  fliptets[1].ver = 11;
8239  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
8240  setelemmarker(fliptets[1].tet, 0);
8241  if (checksubsegflag) {
8242  // Dealloc the space to subsegments.
8243  if (fliptets[0].tet[8] != NULL) {
8244  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
8245  fliptets[0].tet[8] = NULL;
8246  }
8247  if (fliptets[1].tet[8] != NULL) {
8248  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
8249  fliptets[1].tet[8] = NULL;
8250  }
8251  }
8252  if (checksubfaceflag) {
8253  // Dealloc the space to subfaces.
8254  if (fliptets[0].tet[9] != NULL) {
8255  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
8256  fliptets[0].tet[9] = NULL;
8257  }
8258  if (fliptets[1].tet[9] != NULL) {
8259  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
8260  fliptets[1].tet[9] = NULL;
8261  }
8262  }
8263  if (checksubfaceflag) {
8264  if (scount > 0) {
8265  // The element attributes and volume constraint must be set correctly.
8266  // There are two subfaces involved in this flip. The three tets are
8267  // separated into two different regions, one may be exterior. The
8268  // first region has two tets, and the second region has only one.
8269  // The two created tets must be in the same region as the first region.
8270  // The element attributes and volume constraint must be set correctly.
8271  //assert(spivot != -1);
8272  // The tet fliptets[spivot] is in the first region.
8273  for (j = 0; j < 2; j++) {
8274  for (i = 0; i < numelemattrib; i++) {
8275  attrib = elemattribute(fliptets[spivot].tet, i);
8276  setelemattribute(fliptets[j].tet, i, attrib);
8277  }
8278  if (b->varvolume) {
8279  volume = volumebound(fliptets[spivot].tet);
8280  setvolumebound(fliptets[j].tet, volume);
8281  }
8282  }
8283  }
8284  }
8285  // Delete an old tet.
8286  tetrahedrondealloc(fliptets[2].tet);
8287 
8288  if (hullflag > 0) {
8289  // Check if c is dummypointc.
8290  if (pc != dummypoint) {
8291  // Check if d is dummypoint.
8292  if (pd != dummypoint) {
8293  // No hull tet is involved.
8294  } else {
8295  // We deleted three hull tets, and created one hull tet.
8296  hullsize -= 2;
8297  }
8298  setvertices(fliptets[0], pa, pb, pc, pd);
8299  setvertices(fliptets[1], pb, pa, pc, pe);
8300  } else {
8301  // c is dummypoint. The two new tets are hull tets.
8302  setvertices(fliptets[0], pb, pa, pd, pc);
8303  setvertices(fliptets[1], pa, pb, pe, pc);
8304  // Adjust badc -> abcd.
8305  esymself(fliptets[0]);
8306  // Adjust abec -> bace.
8307  esymself(fliptets[1]);
8308  // The hullsize does not change.
8309  }
8310  } else {
8311  setvertices(fliptets[0], pa, pb, pc, pd);
8312  setvertices(fliptets[1], pb, pa, pc, pe);
8313  }
8314 
8315  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
8316  REAL volneg[3], volpos[2], vol_diff;
8317  if (pc != dummypoint) {
8318  if (pd != dummypoint) {
8319  volneg[0] = tetprismvol(pe, pd, pa, pb);
8320  volneg[1] = tetprismvol(pe, pd, pb, pc);
8321  volneg[2] = tetprismvol(pe, pd, pc, pa);
8322  volpos[0] = tetprismvol(pa, pb, pc, pd);
8323  volpos[1] = tetprismvol(pb, pa, pc, pe);
8324  } else { // pd == dummypoint
8325  volneg[0] = 0.;
8326  volneg[1] = 0.;
8327  volneg[2] = 0.;
8328  volpos[0] = 0.;
8329  volpos[1] = tetprismvol(pb, pa, pc, pe);
8330  }
8331  } else { // pc == dummypoint.
8332  volneg[0] = tetprismvol(pe, pd, pa, pb);
8333  volneg[1] = 0.;
8334  volneg[2] = 0.;
8335  volpos[0] = 0.;
8336  volpos[1] = 0.;
8337  }
8338  vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
8339  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
8340  }
8341 
8342  // Bond abcd <==> bace.
8343  bond(fliptets[0], fliptets[1]);
8344  // Bond new faces to top outer boundary faces (at abcd).
8345  for (i = 0; i < 3; i++) {
8346  esym(fliptets[0], newface);
8347  bond(newface, topcastets[i]);
8348  enextself(fliptets[0]);
8349  }
8350  // Bond new faces to bottom outer boundary faces (at bace).
8351  for (i = 0; i < 3; i++) {
8352  esym(fliptets[1], newface);
8353  bond(newface, botcastets[i]);
8354  eprevself(fliptets[1]);
8355  }
8356 
8357  if (checksubsegflag) {
8358  // Bond 9 segments to new (flipped) tets.
8359  for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.
8360  if (issubseg(topcastets[i])) {
8361  tsspivot1(topcastets[i], checkseg);
8362  tssbond1(fliptets[0], checkseg);
8363  sstbond1(checkseg, fliptets[0]);
8364  tssbond1(fliptets[1], checkseg);
8365  sstbond1(checkseg, fliptets[1]);
8366  if (fc->chkencflag & 1) {
8367  enqueuesubface(badsubsegs, &checkseg);
8368  }
8369  }
8370  enextself(fliptets[0]);
8371  eprevself(fliptets[1]);
8372  }
8373  // The three top edges.
8374  for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
8375  esym(fliptets[0], newface);
8376  eprevself(newface);
8377  enext(topcastets[i], casface);
8378  if (issubseg(casface)) {
8379  tsspivot1(casface, checkseg);
8380  tssbond1(newface, checkseg);
8381  sstbond1(checkseg, newface);
8382  if (fc->chkencflag & 1) {
8383  enqueuesubface(badsubsegs, &checkseg);
8384  }
8385  }
8386  enextself(fliptets[0]);
8387  }
8388  // The three bot edges.
8389  for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
8390  esym(fliptets[1], newface);
8391  enextself(newface);
8392  eprev(botcastets[i], casface);
8393  if (issubseg(casface)) {
8394  tsspivot1(casface, checkseg);
8395  tssbond1(newface, checkseg);
8396  sstbond1(checkseg, newface);
8397  if (fc->chkencflag & 1) {
8398  enqueuesubface(badsubsegs, &checkseg);
8399  }
8400  }
8401  eprevself(fliptets[1]);
8402  }
8403  } // if (checksubsegflag)
8404 
8405  if (checksubfaceflag) {
8406  face checksh;
8407  // Bond the top three casing subfaces.
8408  for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
8409  if (issubface(topcastets[i])) {
8410  tspivot(topcastets[i], checksh);
8411  esym(fliptets[0], newface);
8412  sesymself(checksh);
8413  tsbond(newface, checksh);
8414  if (fc->chkencflag & 2) {
8415  enqueuesubface(badsubfacs, &checksh);
8416  }
8417  }
8418  enextself(fliptets[0]);
8419  }
8420  // Bond the bottom three casing subfaces.
8421  for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
8422  if (issubface(botcastets[i])) {
8423  tspivot(botcastets[i], checksh);
8424  esym(fliptets[1], newface);
8425  sesymself(checksh);
8426  tsbond(newface, checksh);
8427  if (fc->chkencflag & 2) {
8428  enqueuesubface(badsubfacs, &checksh);
8429  }
8430  }
8431  eprevself(fliptets[1]);
8432  }
8433 
8434  if (scount > 0) {
8435  face flipfaces[2];
8436  // Perform a 2-to-2 flip in subfaces.
8437  flipfaces[0] = flipshs[(spivot + 1) % 3];
8438  flipfaces[1] = flipshs[(spivot + 2) % 3];
8439  sesymself(flipfaces[1]);
8440  flip22(flipfaces, 0, fc->chkencflag);
8441  // Connect the flipped subfaces to flipped tets.
8442  // First go to the corresponding flipping edge.
8443  // Re-use top- and botcastets[0].
8444  topcastets[0] = fliptets[0];
8445  botcastets[0] = fliptets[1];
8446  for (i = 0; i < ((spivot + 1) % 3); i++) {
8447  enextself(topcastets[0]);
8448  eprevself(botcastets[0]);
8449  }
8450  // Connect the top subface to the top tets.
8451  esymself(topcastets[0]);
8452  sesymself(flipfaces[0]);
8453  // Check if there already exists a subface.
8454  tspivot(topcastets[0], checksh);
8455  if (checksh.sh == NULL) {
8456  tsbond(topcastets[0], flipfaces[0]);
8457  fsymself(topcastets[0]);
8458  sesymself(flipfaces[0]);
8459  tsbond(topcastets[0], flipfaces[0]);
8460  } else {
8461  // An invalid 2-to-2 flip. Report a bug.
8462  terminatetetgen(this, 2);
8463  }
8464  // Connect the bot subface to the bottom tets.
8465  esymself(botcastets[0]);
8466  sesymself(flipfaces[1]);
8467  // Check if there already exists a subface.
8468  tspivot(botcastets[0], checksh);
8469  if (checksh.sh == NULL) {
8470  tsbond(botcastets[0], flipfaces[1]);
8471  fsymself(botcastets[0]);
8472  sesymself(flipfaces[1]);
8473  tsbond(botcastets[0], flipfaces[1]);
8474  } else {
8475  // An invalid 2-to-2 flip. Report a bug.
8476  terminatetetgen(this, 2);
8477  }
8478  } // if (scount > 0)
8479  } // if (checksubfaceflag)
8480 
8481  if (fc->chkencflag & 4) {
8482  // Put two new tets into check list.
8483  for (i = 0; i < 2; i++) {
8484  enqueuetetrahedron(&(fliptets[i]));
8485  }
8486  }
8487 
8488  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8489  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8490  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8491  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8492  setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
8493 
8494  if (hullflag > 0) {
8495  if (dummyflag != 0) {
8496  // Restore the original position of the points (for flipnm()).
8497  if (dummyflag == -1) {
8498  // e were dummypoint. Swap the two new tets.
8499  newface = fliptets[0];
8500  fliptets[0] = fliptets[1];
8501  fliptets[1] = newface;
8502  } else {
8503  // a or b was dummypoint.
8504  if (dummyflag == 1) {
8505  eprevself(fliptets[0]);
8506  enextself(fliptets[1]);
8507  } else { // dummyflag == 2
8508  enextself(fliptets[0]);
8509  eprevself(fliptets[1]);
8510  }
8511  }
8512  }
8513  }
8514 
8515  if (fc->enqflag > 0) {
8516  // Queue faces which may be locally non-Delaunay.
8517  // pa = org(fliptets[0]); // 'a' may be a new vertex.
8518  enextesym(fliptets[0], newface);
8519  flippush(flipstack, &newface);
8520  eprevesym(fliptets[1], newface);
8521  flippush(flipstack, &newface);
8522  if (fc->enqflag > 1) {
8523  //pb = dest(fliptets[0]);
8524  eprevesym(fliptets[0], newface);
8525  flippush(flipstack, &newface);
8526  enextesym(fliptets[1], newface);
8527  flippush(flipstack, &newface);
8528  //pc = apex(fliptets[0]);
8529  esym(fliptets[0], newface);
8530  flippush(flipstack, &newface);
8531  esym(fliptets[1], newface);
8532  flippush(flipstack, &newface);
8533  }
8534  }
8535 
8536  recenttet = fliptets[0];
8537 }
8538 
8540 // //
8541 // flip41() Perform a 4-to-1 flip (Remove a vertex). //
8542 // //
8543 // 'fliptets' is an array of four tetrahedra in the star of the removing //
8544 // vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
8545 // four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
8546 // p]. On return, 'fliptets[0]' is the new tet [a,b,c,d]. //
8547 // //
8548 // If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
8549 // The 'hullsize' may be changed. Note that p may be dummypoint. In this //
8550 // case, four hull tets are replaced by one real tet. //
8551 // //
8552 // If 'checksubface' flag is set (>0), it is possible that there are three //
8553 // interior subfaces connecting at p. If so, a 3-to-1 flip is performed to //
8554 // to remove p from the surface triangulation. //
8555 // //
8556 // If it is called by the routine incrementalflip(), we assume that d is the //
8557 // newly inserted vertex. //
8558 // //
8560 
8561 void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
8562 {
8563  triface topcastets[3], botcastet;
8564  triface newface, neightet;
8565  face flipshs[4];
8566  point pa, pb, pc, pd, pp;
8567  int dummyflag = 0; // in {0, 1, 2, 3, 4}
8568  int spivot = -1, scount = 0;
8569  int t1ver;
8570  int i;
8571 
8572  pa = org(fliptets[3]);
8573  pb = dest(fliptets[3]);
8574  pc = apex(fliptets[3]);
8575  pd = dest(fliptets[0]);
8576  pp = org(fliptets[0]); // The removing vertex.
8577 
8578  flip41count++;
8579 
8580  // Get the outer boundary faces.
8581  for (i = 0; i < 3; i++) {
8582  enext(fliptets[i], topcastets[i]);
8583  fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
8584  enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
8585  }
8586  fsym(fliptets[3], botcastet); // [b,a,c,#]
8587 
8588  if (checksubfaceflag) {
8589  // Check if there are three subfaces at 'p'.
8590  // Re-use 'newface'.
8591  for (i = 0; i < 3; i++) {
8592  fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
8593  tspivot(newface, flipshs[i]);
8594  if (flipshs[i].sh != NULL) {
8595  spivot = i; // Remember this subface.
8596  scount++;
8597  }
8598  enextself(fliptets[3]);
8599  }
8600  if (scount > 0) {
8601  // There are three subfaces connecting at p.
8602  if (scount < 3) {
8603  // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
8604  // Go to the tet containing the three subfaces.
8605  fsym(topcastets[spivot], neightet);
8606  // Get the three subfaces connecting at p.
8607  for (i = 0; i < 3; i++) {
8608  esym(neightet, newface);
8609  tspivot(newface, flipshs[i]);
8610  eprevself(neightet);
8611  }
8612  } else {
8613  spivot = 3; // The new subface is [a,b,c].
8614  }
8615  }
8616  } // if (checksubfaceflag)
8617 
8618 
8619  // Re-use fliptets[0] for [a,b,c,d].
8620  fliptets[0].ver = 11;
8621  setelemmarker(fliptets[0].tet, 0); // Clean all flags.
8622  // NOTE: the element attributes and volume constraint remain unchanged.
8623  if (checksubsegflag) {
8624  // Dealloc the space to subsegments.
8625  if (fliptets[0].tet[8] != NULL) {
8626  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
8627  fliptets[0].tet[8] = NULL;
8628  }
8629  }
8630  if (checksubfaceflag) {
8631  // Dealloc the space to subfaces.
8632  if (fliptets[0].tet[9] != NULL) {
8633  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
8634  fliptets[0].tet[9] = NULL;
8635  }
8636  }
8637  // Delete the other three tets.
8638  for (i = 1; i < 4; i++) {
8639  tetrahedrondealloc(fliptets[i].tet);
8640  }
8641 
8642  if (pp != dummypoint) {
8643  // Mark the point pp as unused.
8644  setpointtype(pp, UNUSEDVERTEX);
8645  unuverts++;
8646  }
8647 
8648  // Create the new tet [a,b,c,d].
8649  if (hullflag > 0) {
8650  // One of the five vertices may be 'dummypoint'.
8651  if (pa == dummypoint) {
8652  // pa is dummypoint.
8653  setvertices(fliptets[0], pc, pb, pd, pa);
8654  esymself(fliptets[0]); // [b,c,a,d]
8655  eprevself(fliptets[0]); // [a,b,c,d]
8656  dummyflag = 1;
8657  } else if (pb == dummypoint) {
8658  setvertices(fliptets[0], pa, pc, pd, pb);
8659  esymself(fliptets[0]); // [c,a,b,d]
8660  enextself(fliptets[0]); // [a,b,c,d]
8661  dummyflag = 2;
8662  } else if (pc == dummypoint) {
8663  setvertices(fliptets[0], pb, pa, pd, pc);
8664  esymself(fliptets[0]); // [a,b,c,d]
8665  dummyflag = 3;
8666  } else if (pd == dummypoint) {
8667  setvertices(fliptets[0], pa, pb, pc, pd);
8668  dummyflag = 4;
8669  } else {
8670  setvertices(fliptets[0], pa, pb, pc, pd);
8671  if (pp == dummypoint) {
8672  dummyflag = -1;
8673  } else {
8674  dummyflag = 0;
8675  }
8676  }
8677  if (dummyflag > 0) {
8678  // We deleted 3 hull tets, and create 1 hull tet.
8679  hullsize -= 2;
8680  } else if (dummyflag < 0) {
8681  // We deleted 4 hull tets.
8682  hullsize -= 4;
8683  // meshedges does not change.
8684  }
8685  } else {
8686  setvertices(fliptets[0], pa, pb, pc, pd);
8687  }
8688 
8689  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
8690  REAL volneg[4], volpos[1], vol_diff;
8691  if (dummyflag > 0) {
8692  if (pa == dummypoint) {
8693  volneg[0] = 0.;
8694  volneg[1] = tetprismvol(pp, pd, pb, pc);
8695  volneg[2] = 0.;
8696  volneg[3] = 0.;
8697  } else if (pb == dummypoint) {
8698  volneg[0] = 0.;
8699  volneg[1] = 0.;
8700  volneg[2] = tetprismvol(pp, pd, pc, pa);
8701  volneg[3] = 0.;
8702  } else if (pc == dummypoint) {
8703  volneg[0] = tetprismvol(pp, pd, pa, pb);
8704  volneg[1] = 0.;
8705  volneg[2] = 0.;
8706  volneg[3] = 0.;
8707  } else { // pd == dummypoint
8708  volneg[0] = 0.;
8709  volneg[1] = 0.;
8710  volneg[2] = 0.;
8711  volneg[3] = tetprismvol(pa, pb, pc, pp);
8712  }
8713  volpos[0] = 0.;
8714  } else if (dummyflag < 0) {
8715  volneg[0] = 0.;
8716  volneg[1] = 0.;
8717  volneg[2] = 0.;
8718  volneg[3] = 0.;
8719  volpos[0] = tetprismvol(pa, pb, pc, pd);
8720  } else {
8721  volneg[0] = tetprismvol(pp, pd, pa, pb);
8722  volneg[1] = tetprismvol(pp, pd, pb, pc);
8723  volneg[2] = tetprismvol(pp, pd, pc, pa);
8724  volneg[3] = tetprismvol(pa, pb, pc, pp);
8725  volpos[0] = tetprismvol(pa, pb, pc, pd);
8726  }
8727  vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
8728  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
8729  }
8730 
8731  // Bond the new tet to adjacent tets.
8732  for (i = 0; i < 3; i++) {
8733  esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
8734  bond(newface, topcastets[i]);
8735  enextself(fliptets[0]);
8736  }
8737  bond(fliptets[0], botcastet);
8738 
8739  if (checksubsegflag) {
8740  face checkseg;
8741  // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
8742  for (i = 0; i < 3; i++) {
8743  eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
8744  if (issubseg(newface)) {
8745  tsspivot1(newface, checkseg);
8746  esym(fliptets[0], newface);
8747  enextself(newface); // At edges [a,d], [b,d], [c,d].
8748  tssbond1(newface, checkseg);
8749  sstbond1(checkseg, newface);
8750  if (fc->chkencflag & 1) {
8751  enqueuesubface(badsubsegs, &checkseg);
8752  }
8753  }
8754  enextself(fliptets[0]);
8755  }
8756  for (i = 0; i < 3; i++) {
8757  if (issubseg(topcastets[i])) {
8758  tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
8759  tssbond1(fliptets[0], checkseg);
8760  sstbond1(checkseg, fliptets[0]);
8761  if (fc->chkencflag & 1) {
8762  enqueuesubface(badsubsegs, &checkseg);
8763  }
8764  }
8765  enextself(fliptets[0]);
8766  }
8767  }
8768 
8769  if (checksubfaceflag) {
8770  face checksh;
8771  // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
8772  for (i = 0; i < 3; i++) {
8773  if (issubface(topcastets[i])) {
8774  tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
8775  esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
8776  sesymself(checksh);
8777  tsbond(newface, checksh);
8778  if (fc->chkencflag & 2) {
8779  enqueuesubface(badsubfacs, &checksh);
8780  }
8781  }
8782  enextself(fliptets[0]);
8783  }
8784  if (issubface(botcastet)) {
8785  tspivot(botcastet, checksh); // At face [b,a,c]
8786  sesymself(checksh);
8787  tsbond(fliptets[0], checksh);
8788  if (fc->chkencflag & 2) {
8789  enqueuesubface(badsubfacs, &checksh);
8790  }
8791  }
8792 
8793  if (spivot >= 0) {
8794  // Perform a 3-to-1 flip in surface triangulation.
8795  // Depending on the value of 'spivot', the three subfaces are:
8796  // - 0: [a,b,p], [b,d,p], [d,a,p]
8797  // - 1: [b,c,p], [c,d,p], [d,b,p]
8798  // - 2: [c,a,p], [a,d,p], [d,c,p]
8799  // - 3: [a,b,p], [b,c,p], [c,a,p]
8800  // Adjust the three subfaces such that their origins are p, i.e.,
8801  // - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
8802  for (i = 0; i < 3; i++) {
8803  senext2self(flipshs[i]);
8804  }
8805  flip31(flipshs, 0);
8806  // Delete the three old subfaces.
8807  for (i = 0; i < 3; i++) {
8808  shellfacedealloc(subfaces, flipshs[i].sh);
8809  }
8810  if (spivot < 3) {
8811  // // Bond the new subface to the new tet [a,b,c,d].
8812  tsbond(topcastets[spivot], flipshs[3]);
8813  fsym(topcastets[spivot], newface);
8814  sesym(flipshs[3], checksh);
8815  tsbond(newface, checksh);
8816  } else {
8817  // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
8818  tsbond(fliptets[0], flipshs[3]);
8819  fsym(fliptets[0], newface);
8820  sesym(flipshs[3], checksh);
8821  tsbond(newface, checksh);
8822  }
8823  } // if (spivot > 0)
8824  } // if (checksubfaceflag)
8825 
8826  if (fc->chkencflag & 4) {
8827  enqueuetetrahedron(&(fliptets[0]));
8828  }
8829 
8830  // Update the point-to-tet map.
8831  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8832  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8833  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8834  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8835 
8836  if (fc->enqflag > 0) {
8837  // Queue faces which may be locally non-Delaunay.
8838  flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
8839  if (fc->enqflag > 1) {
8840  for (i = 0; i < 3; i++) {
8841  esym(fliptets[0], newface);
8842  flippush(flipstack, &newface);
8843  enextself(fliptets[0]);
8844  }
8845  }
8846  }
8847 
8848  recenttet = fliptets[0];
8849 }
8850 
8852 // //
8853 // flipnm() Flip an edge through a sequence of elementary flips. //
8854 // //
8855 // 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
8856 // ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
8857 // use the right-hand rule. //
8858 // //
8859 // 'level' (>= 0) indicates the current link level. If 'level > 0', we are //
8860 // flipping a link edge of an edge [a',b'], and 'abedgepivot' indicates //
8861 // which link edge, i.e., [c',b'] or [a',c'], is [a,b] These two parameters //
8862 // allow us to determine the new tets after a 3-to-2 flip, i.e., tets that //
8863 // do not inside the reduced star of edge [a',b']. //
8864 // //
8865 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8866 // in flipnm([a,b]) so that the mesh is returned to its original state //
8867 // before doing the flipnm([a,b]) operation. //
8868 // //
8869 // The return value is an integer nn, where nn <= n. If nn is 2, then the //
8870 // edge is flipped. The first and the second tets in 'abtets' are new tets. //
8871 // Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets //
8872 // in the current star of [a,b]. //
8873 // //
8874 // ASSUMPTIONS: //
8875 // - Neither a nor b is 'dummypoint'. //
8876 // - [a,b] must not be a segment. //
8877 // //
8879 
8880 int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
8881  flipconstraints* fc)
8882 {
8883  triface fliptets[3], spintet, flipedge;
8884  triface *tmpabtets, *parytet;
8885  point pa, pb, pc, pd, pe, pf;
8886  REAL ori;
8887  int hullflag, hulledgeflag;
8888  int reducflag, rejflag;
8889  int reflexlinkedgecount;
8890  int edgepivot;
8891  int n1, nn;
8892  int t1ver;
8893  int i, j;
8894 
8895  pa = org(abtets[0]);
8896  pb = dest(abtets[0]);
8897 
8898  if (n > 3) {
8899  // Try to reduce the size of the Star(ab) by flipping a face in it.
8900  reflexlinkedgecount = 0;
8901 
8902  for (i = 0; i < n; i++) {
8903  // Let the face of 'abtets[i]' be [a,b,c].
8904  if (checksubfaceflag) {
8905  if (issubface(abtets[i])) {
8906  continue; // Skip a subface.
8907  }
8908  }
8909  // Do not flip this face if it is involved in two Stars.
8910  if ((elemcounter(abtets[i]) > 1) ||
8911  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8912  continue;
8913  }
8914 
8915  pc = apex(abtets[i]);
8916  pd = apex(abtets[(i + 1) % n]);
8917  pe = apex(abtets[(i - 1 + n) % n]);
8918  if ((pd == dummypoint) || (pe == dummypoint)) {
8919  continue; // [a,b,c] is a hull face.
8920  }
8921 
8922 
8923  // Decide whether [a,b,c] is flippable or not.
8924  reducflag = 0;
8925 
8926  hullflag = (pc == dummypoint); // pc may be dummypoint.
8927  hulledgeflag = 0;
8928  if (hullflag == 0) {
8929  ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
8930  if (ori > 0) {
8931  ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
8932  if (ori > 0) {
8933  // Test if [a,b] is locally convex OR flat.
8934  ori = orient3d(pa, pb, pd, pe);
8935  if (ori > 0) {
8936  // Found a 2-to-3 flip: [a,b,c] => [e,d]
8937  reducflag = 1;
8938  } else if (ori == 0) {
8939  // [a,b] is flat.
8940  if (n == 4) {
8941  // The "flat" tet can be removed immediately by a 3-to-2 flip.
8942  reducflag = 1;
8943  // Check if [e,d] is a hull edge.
8944  pf = apex(abtets[(i + 2) % n]);
8945  hulledgeflag = (pf == dummypoint);
8946  }
8947  }
8948  }
8949  }
8950  if (!reducflag) {
8951  reflexlinkedgecount++;
8952  }
8953  } else {
8954  // 'c' is dummypoint.
8955  if (n == 4) {
8956  // Let the vertex opposite to 'c' is 'f'.
8957  // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
8958  // are valid tets.
8959  // Note: When the mesh is not convex, it is possible that [a,b] is
8960  // locally non-convex (at hull faces [a,b,e] and [b,a,d]).
8961  // In this case, an edge flip [a,b] to [e,d] is still possible.
8962  pf = apex(abtets[(i + 2) % n]);
8963  ori = orient3d(pd, pe, pf, pa);
8964  if (ori < 0) {
8965  ori = orient3d(pe, pd, pf, pb);
8966  if (ori < 0) {
8967  // Found a 4-to-4 flip: [a,b] => [e,d]
8968  reducflag = 1;
8969  ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
8970  hulledgeflag = 1; // [e,d] is a hull edge.
8971  }
8972  }
8973  }
8974  } // if (hullflag)
8975 
8976  if (reducflag) {
8977  if (nonconvex && hulledgeflag) {
8978  // We will create a hull edge [e,d]. Make sure it does not exist.
8979  if (getedge(pe, pd, &spintet)) {
8980  // The 2-to-3 flip is not a topological valid flip.
8981  reducflag = 0;
8982  }
8983  }
8984  }
8985 
8986  if (reducflag) {
8987  // [a,b,c] could be removed by a 2-to-3 flip.
8988  rejflag = 0;
8989  if (fc->checkflipeligibility) {
8990  // Check if the flip can be performed.
8991  rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
8992  abedgepivot, fc);
8993  }
8994  if (!rejflag) {
8995  // Do flip: [a,b,c] => [e,d].
8996  fliptets[0] = abtets[i];
8997  fsym(fliptets[0], fliptets[1]); // abtets[i-1].
8998  flip23(fliptets, hullflag, fc);
8999 
9000  // Shrink the array 'abtets', maintain the original order.
9001  // Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
9002  // are flipped, i.e., they do not in Star(ab) anymore.
9003  // 'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
9004  // 'abtets[i-1]' (adjust it to be [a,b,e,d]), see below:
9005  //
9006  // before after
9007  // [0] |___________| [0] |___________|
9008  // ... |___________| ... |___________|
9009  // [i-1] |_[a,b,e,c]_| [i-1] |_[a,b,e,d]_|
9010  // [i] |_[a,b,c,d]_| --> [i] |_[a,b,d,#]_|
9011  // [i+1] |_[a,b,d,#]_| [i+1] |_[a,b,#,*]_|
9012  // ... |___________| ... |___________|
9013  // [n-2] |___________| [n-2] |___________|
9014  // [n-1] |___________| [n-1] |_[i]_2-t-3_|
9015  //
9016  edestoppoself(fliptets[0]); // [a,b,e,d]
9017  // Increase the counter of this new tet (it is in Star(ab)).
9018  increaseelemcounter(fliptets[0]);
9019  abtets[(i - 1 + n) % n] = fliptets[0];
9020  for (j = i; j < n - 1; j++) {
9021  abtets[j] = abtets[j + 1]; // Upshift
9022  }
9023  // The last entry 'abtets[n-1]' is empty. It is used in two ways:
9024  // (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
9025  // (ii) it remembers the position [i] where this flip took place.
9026  // These information let us to either undo this flip or recover
9027  // the original edge link (for collecting new created tets).
9028  abtets[n - 1].tet = (tetrahedron *) pc;
9029  abtets[n - 1].ver = 0; // Clear it.
9030  // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
9031  // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
9032  abtets[n - 1].ver |= (1 << 4);
9033  // The poisition [i] of this flip is saved above the 7th bit.
9034  abtets[n - 1].ver |= (i << 6);
9035 
9036  if (fc->collectnewtets) {
9037  // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
9038  // Re-use the global array 'cavetetlist'.
9039  for (j = 1; j < 3; j++) {
9040  cavetetlist->newindex((void **) &parytet);
9041  *parytet = fliptets[j]; // fliptets[1], fliptets[2].
9042  }
9043  }
9044 
9045  // Star(ab) is reduced. Try to flip the edge [a,b].
9046  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
9047 
9048  if (nn == 2) {
9049  // The edge has been flipped.
9050  return nn;
9051  } else { // if (nn > 2)
9052  // The edge is not flipped.
9053  if (fc->unflip || (ori == 0)) {
9054  // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to
9055  // transform [e,d] => [a,b,c].
9056  // 'ori == 0' means that the previous flip created a degenerated
9057  // tet. It must be removed.
9058  // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to
9059  // find another two tets [e,d,b,c] and [e,d,c,a].
9060  fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
9061  edestoppoself(fliptets[0]); // [e,d,a,b]
9062  fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
9063  fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
9064  // Restore the two original tets in Star(ab).
9065  flip32(fliptets, hullflag, fc);
9066  // Marktest the two restored tets in Star(ab).
9067  for (j = 0; j < 2; j++) {
9068  increaseelemcounter(fliptets[j]);
9069  }
9070  // Expand the array 'abtets', maintain the original order.
9071  for (j = n - 2; j>= i; j--) {
9072  abtets[j + 1] = abtets[j]; // Downshift
9073  }
9074  // Insert the two new tets 'fliptets[0]' [a,b,c,d] and
9075  // 'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries,
9076  // respectively.
9077  esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
9078  abtets[i] = fliptets[0]; // [a,b,c,d]
9079  nn++;
9080  if (fc->collectnewtets) {
9081  // Pop two (flipped) tets from the stack.
9082  cavetetlist->objects -= 2;
9083  }
9084  } // if (unflip || (ori == 0))
9085  } // if (nn > 2)
9086 
9087  if (!fc->unflip) {
9088  // The flips are not reversed. The current Star(ab) can not be
9089  // further reduced. Return its current size (# of tets).
9090  return nn;
9091  }
9092  // unflip is set.
9093  // Continue the search for flips.
9094  }
9095  } // if (reducflag)
9096  } // i
9097 
9098  // The Star(ab) is not reduced.
9099  if (reflexlinkedgecount > 0) {
9100  // There are reflex edges in the Link(ab).
9101  if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) ||
9102  ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
9103  // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
9104  for (i = 0; i < n; i++) {
9105  // Do not flip this face [a,b,c] if there are two Stars involved.
9106  if ((elemcounter(abtets[i]) > 1) ||
9107  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
9108  continue;
9109  }
9110  pc = apex(abtets[i]);
9111  if (pc == dummypoint) {
9112  continue; // [a,b] is a hull edge.
9113  }
9114  pd = apex(abtets[(i + 1) % n]);
9115  pe = apex(abtets[(i - 1 + n) % n]);
9116  if ((pd == dummypoint) || (pe == dummypoint)) {
9117  continue; // [a,b,c] is a hull face.
9118  }
9119 
9120 
9121  edgepivot = 0; // No edge is selected yet.
9122 
9123  // Test if [b,c] is locally convex or flat.
9124  ori = orient3d(pb, pc, pd, pe);
9125  if (ori <= 0) {
9126  // Select the edge [c,b].
9127  enext(abtets[i], flipedge); // [b,c,a,d]
9128  edgepivot = 1;
9129  }
9130  if (!edgepivot) {
9131  // Test if [c,a] is locally convex or flat.
9132  ori = orient3d(pc, pa, pd, pe);
9133  if (ori <= 0) {
9134  // Select the edge [a,c].
9135  eprev(abtets[i], flipedge); // [c,a,b,d].
9136  edgepivot = 2;
9137  }
9138  }
9139 
9140  if (!edgepivot) continue;
9141 
9142  // An edge is selected.
9143  if (checksubsegflag) {
9144  // Do not flip it if it is a segment.
9145  if (issubseg(flipedge)) {
9146  if (fc->collectencsegflag) {
9147  face checkseg, *paryseg;
9148  tsspivot1(flipedge, checkseg);
9149  if (!sinfected(checkseg)) {
9150  // Queue this segment in list.
9151  sinfect(checkseg);
9152  caveencseglist->newindex((void **) &paryseg);
9153  *paryseg = checkseg;
9154  }
9155  }
9156  continue;
9157  }
9158  }
9159 
9160  // Try to flip the selected edge ([c,b] or [a,c]).
9161  esymself(flipedge);
9162  // Count the number of tets at the edge.
9163  n1 = 0;
9164  j = 0; // Sum of the star counters.
9165  spintet = flipedge;
9166  while (1) {
9167  n1++;
9168  j += (elemcounter(spintet));
9169  fnextself(spintet);
9170  if (spintet.tet == flipedge.tet) break;
9171  }
9172  if (n1 < 3) {
9173  // This is only possible when the mesh contains inverted
9174  // elements. Reprot a bug.
9175  terminatetetgen(this, 2);
9176  }
9177  if (j > 2) {
9178  // The Star(flipedge) overlaps other Stars.
9179  continue; // Do not flip this edge.
9180  }
9181 
9182  if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
9183  // The star size exceeds the given limit.
9184  continue; // Do not flip it.
9185  }
9186 
9187  // Allocate spaces for Star(flipedge).
9188  tmpabtets = new triface[n1];
9189  // Form the Star(flipedge).
9190  j = 0;
9191  spintet = flipedge;
9192  while (1) {
9193  tmpabtets[j] = spintet;
9194  // Increase the star counter of this tet.
9195  increaseelemcounter(tmpabtets[j]);
9196  j++;
9197  fnextself(spintet);
9198  if (spintet.tet == flipedge.tet) break;
9199  }
9200 
9201  // Try to flip the selected edge away.
9202  nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
9203 
9204  if (nn == 2) {
9205  // The edge is flipped. Star(ab) is reduced.
9206  // Shrink the array 'abtets', maintain the original order.
9207  if (edgepivot == 1) {
9208  // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
9209  spintet = tmpabtets[0]; // [d,a,e,b]
9210  enextself(spintet);
9211  esymself(spintet);
9212  enextself(spintet); // [a,b,e,d]
9213  } else {
9214  // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
9215  spintet = tmpabtets[1]; // [b,d,e,a]
9216  eprevself(spintet);
9217  esymself(spintet);
9218  eprevself(spintet); // [a,b,e,d]
9219  } // edgepivot == 2
9220  increaseelemcounter(spintet); // It is in Star(ab).
9221  // Put the new tet at [i-1]-th entry.
9222  abtets[(i - 1 + n) % n] = spintet;
9223  for (j = i; j < n - 1; j++) {
9224  abtets[j] = abtets[j + 1]; // Upshift
9225  }
9226  // Remember the flips in the last entry of the array 'abtets'.
9227  // They can be used to recover the flipped edge.
9228  abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
9229  abtets[n - 1].ver = 0; // Clear it.
9230  // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
9231  abtets[n - 1].ver |= edgepivot;
9232  // Use the 6th bit to signal this n1-to-m1 flip.
9233  abtets[n - 1].ver |= (1 << 5);
9234  // The poisition [i] of this flip is saved from 7th to 19th bit.
9235  abtets[n - 1].ver |= (i << 6);
9236  // The size of the star 'n1' is saved from 20th bit.
9237  abtets[n - 1].ver |= (n1 << 19);
9238 
9239  // Remember the flipped link vertex 'c'. It can be used to recover
9240  // the original edge link of [a,b], and to collect new tets.
9241  tmpabtets[0].tet = (tetrahedron *) pc;
9242  tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
9243 
9244  // Continue to flip the edge [a,b].
9245  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
9246 
9247  if (nn == 2) {
9248  // The edge has been flipped.
9249  return nn;
9250  } else { // if (nn > 2) {
9251  // The edge is not flipped.
9252  if (fc->unflip) {
9253  // Recover the flipped edge ([c,b] or [a,c]).
9254  // The sequence of flips are saved in 'tmpabtets'.
9255  // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
9256  // the flipping of edge [c,b] or [a,c].It must still exist in
9257  // Star(ab). It is the start tet to recover the flipped edge.
9258  if (edgepivot == 1) {
9259  // The flip edge is [c,b].
9260  tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
9261  eprevself(tmpabtets[0]);
9262  esymself(tmpabtets[0]);
9263  eprevself(tmpabtets[0]); // [d,a,e,b]
9264  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
9265  } else {
9266  // The flip edge is [a,c].
9267  tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
9268  enextself(tmpabtets[1]);
9269  esymself(tmpabtets[1]);
9270  enextself(tmpabtets[1]); // [b,d,e,a]
9271  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
9272  } // if (edgepivot == 2)
9273 
9274  // Recover the flipped edge ([c,b] or [a,c]).
9275  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9276 
9277  // Insert the two recovered tets into Star(ab).
9278  for (j = n - 2; j >= i; j--) {
9279  abtets[j + 1] = abtets[j]; // Downshift
9280  }
9281  if (edgepivot == 1) {
9282  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
9283  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
9284  // tmpabtets[2] is [c,b,e,d]
9285  fliptets[0] = tmpabtets[1];
9286  enextself(fliptets[0]);
9287  esymself(fliptets[0]); // [a,b,e,c]
9288  fliptets[1] = tmpabtets[0];
9289  esymself(fliptets[1]);
9290  eprevself(fliptets[1]); // [a,b,c,d]
9291  } else {
9292  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
9293  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
9294  // tmpabtets[2] is [a,c,e,d]
9295  fliptets[0] = tmpabtets[1];
9296  eprevself(fliptets[0]);
9297  esymself(fliptets[0]); // [a,b,e,c]
9298  fliptets[1] = tmpabtets[0];
9299  esymself(fliptets[1]);
9300  enextself(fliptets[1]); // [a,b,c,d]
9301  } // edgepivot == 2
9302  for (j = 0; j < 2; j++) {
9303  increaseelemcounter(fliptets[j]);
9304  }
9305  // Insert the two recovered tets into Star(ab).
9306  abtets[(i - 1 + n) % n] = fliptets[0];
9307  abtets[i] = fliptets[1];
9308  nn++;
9309  // Release the allocated spaces.
9310  delete [] tmpabtets;
9311  } // if (unflip)
9312  } // if (nn > 2)
9313 
9314  if (!fc->unflip) {
9315  // The flips are not reversed. The current Star(ab) can not be
9316  // further reduced. Return its size (# of tets).
9317  return nn;
9318  }
9319  // unflip is set.
9320  // Continue the search for flips.
9321  } else {
9322  // The selected edge is not flipped.
9323  if (!fc->unflip) {
9324  // Release the memory used in this attempted flip.
9325  flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
9326  }
9327  // Decrease the star counters of tets in Star(flipedge).
9328  for (j = 0; j < nn; j++) {
9329  decreaseelemcounter(tmpabtets[j]);
9330  }
9331  // Release the allocated spaces.
9332  delete [] tmpabtets;
9333  }
9334  } // i
9335  } // if (level...)
9336  } // if (reflexlinkedgecount > 0)
9337  } else {
9338  // Check if a 3-to-2 flip is possible.
9339  // Let the three apexes be c, d,and e. Hull tets may be involved. If so,
9340  // we rearrange them such that the vertex e is dummypoint.
9341  hullflag = 0;
9342 
9343  if (apex(abtets[0]) == dummypoint) {
9344  pc = apex(abtets[1]);
9345  pd = apex(abtets[2]);
9346  pe = apex(abtets[0]);
9347  hullflag = 1;
9348  } else if (apex(abtets[1]) == dummypoint) {
9349  pc = apex(abtets[2]);
9350  pd = apex(abtets[0]);
9351  pe = apex(abtets[1]);
9352  hullflag = 2;
9353  } else {
9354  pc = apex(abtets[0]);
9355  pd = apex(abtets[1]);
9356  pe = apex(abtets[2]);
9357  hullflag = (pe == dummypoint) ? 3 : 0;
9358  }
9359 
9360  reducflag = 0;
9361  rejflag = 0;
9362 
9363 
9364  if (hullflag == 0) {
9365  // Make sure that no inverted tet will be created, i.e. the new tets
9366  // [d,c,e,a] and [c,d,e,b] must be valid tets.
9367  ori = orient3d(pd, pc, pe, pa);
9368  if (ori < 0) {
9369  ori = orient3d(pc, pd, pe, pb);
9370  if (ori < 0) {
9371  reducflag = 1;
9372  }
9373  }
9374  } else {
9375  // [a,b] is a hull edge.
9376  // Note: This can happen when it is in the middle of a 4-to-4 flip.
9377  // Note: [a,b] may even be a non-convex hull edge.
9378  if (!nonconvex) {
9379  // The mesh is convex, only do flip if it is a coplanar hull edge.
9380  ori = orient3d(pa, pb, pc, pd);
9381  if (ori == 0) {
9382  reducflag = 1;
9383  }
9384  } else { // nonconvex
9385  reducflag = 1;
9386  }
9387  if (reducflag == 1) {
9388  // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
9389  // Make sure that no inverted tet will be created.
9390  point searchpt = NULL, chkpt;
9391  REAL bigvol = 0.0, ori1, ori2;
9392  // Search an interior vertex which is an apex of edge [c,d].
9393  // In principle, it can be arbitrary interior vertex. To avoid
9394  // numerical issue, we choose the vertex which belongs to a tet
9395  // 't' at edge [c,d] and 't' has the biggest volume.
9396  fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
9397  eorgoppoself(fliptets[0]); // [d,c,b,a]
9398  spintet = fliptets[0];
9399  while (1) {
9400  fnextself(spintet);
9401  chkpt = oppo(spintet);
9402  if (chkpt == pb) break;
9403  if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
9404  ori = -orient3d(pd, pc, apex(spintet), chkpt);
9405  if (ori > bigvol) {
9406  bigvol = ori;
9407  searchpt = chkpt;
9408  }
9409  }
9410  }
9411  if (searchpt != NULL) {
9412  // Now valid the configuration.
9413  ori1 = orient3d(pd, pc, searchpt, pa);
9414  ori2 = orient3d(pd, pc, searchpt, pb);
9415  if (ori1 * ori2 >= 0.0) {
9416  reducflag = 0; // Not valid.
9417  } else {
9418  ori1 = orient3d(pa, pb, searchpt, pc);
9419  ori2 = orient3d(pa, pb, searchpt, pd);
9420  if (ori1 * ori2 >= 0.0) {
9421  reducflag = 0; // Not valid.
9422  }
9423  }
9424  } else {
9425  // No valid searchpt is found.
9426  reducflag = 0; // Do not flip it.
9427  }
9428  } // if (reducflag == 1)
9429  } // if (hullflag == 1)
9430 
9431  if (reducflag) {
9432  // A 3-to-2 flip is possible.
9433  if (checksubfaceflag) {
9434  // This edge (must not be a segment) can be flipped ONLY IF it belongs
9435  // to either 0 or 2 subfaces. In the latter case, a 2-to-2 flip in
9436  // the surface mesh will be automatically performed within the
9437  // 3-to-2 flip.
9438  nn = 0;
9439  edgepivot = -1; // Re-use it.
9440  for (j = 0; j < 3; j++) {
9441  if (issubface(abtets[j])) {
9442  nn++; // Found a subface.
9443  } else {
9444  edgepivot = j;
9445  }
9446  }
9447  if (nn == 1) {
9448  // Found only 1 subface containing this edge. This can happen in
9449  // the boundary recovery phase. The neighbor subface is not yet
9450  // recovered. This edge should not be flipped at this moment.
9451  rejflag = 1;
9452  } else if (nn == 2) {
9453  // Found two subfaces. A 2-to-2 flip is possible. Validate it.
9454  // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
9455  eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
9456  if (issubface(spintet)) {
9457  rejflag = 1; // Conflict to a 2-to-2 flip.
9458  } else {
9459  esymself(spintet);
9460  if (issubface(spintet)) {
9461  rejflag = 1; // Conflict to a 2-to-2 flip.
9462  }
9463  }
9464  } else if (nn == 3) {
9465  // Report a bug.
9466  terminatetetgen(this, 2);
9467  }
9468  }
9469  if (!rejflag && fc->checkflipeligibility) {
9470  // Here we must exchange 'a' and 'b'. Since in the check... function,
9471  // we assume the following point sequence, 'a,b,c,d,e', where
9472  // the face [a,b,c] will be flipped and the edge [e,d] will be
9473  // created. The two new tets are [a,b,c,d] and [b,a,c,e].
9474  rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level,
9475  abedgepivot, fc);
9476  }
9477  if (!rejflag) {
9478  // Do flip: [a,b] => [c,d,e]
9479  flip32(abtets, hullflag, fc);
9480  if (fc->remove_ndelaunay_edge) {
9481  if (level == 0) {
9482  // It is the desired removing edge. Check if we have improved
9483  // the objective function.
9484  if ((fc->tetprism_vol_sum >= 0.0) ||
9485  (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
9486  // No improvement! flip back: [c,d,e] => [a,b].
9487  flip23(abtets, hullflag, fc);
9488  // Increase the element counter -- They are in cavity.
9489  for (j = 0; j < 3; j++) {
9490  increaseelemcounter(abtets[j]);
9491  }
9492  return 3;
9493  }
9494  } // if (level == 0)
9495  }
9496  if (fc->collectnewtets) {
9497  // Collect new tets.
9498  if (level == 0) {
9499  // Push the two new tets into stack.
9500  for (j = 0; j < 2; j++) {
9501  cavetetlist->newindex((void **) &parytet);
9502  *parytet = abtets[j];
9503  }
9504  } else {
9505  // Only one of the new tets is collected. The other one is inside
9506  // the reduced edge star. 'abedgepivot' is either '1' or '2'.
9507  cavetetlist->newindex((void **) &parytet);
9508  if (abedgepivot == 1) { // [c,b]
9509  *parytet = abtets[1];
9510  } else {
9511  *parytet = abtets[0];
9512  }
9513  }
9514  } // if (fc->collectnewtets)
9515  return 2;
9516  }
9517  } // if (reducflag)
9518  } // if (n == 3)
9519 
9520  // The current (reduced) Star size.
9521  return n;
9522 }
9523 
9525 // //
9526 // flipnm_post() Post process a n-to-m flip. //
9527 // //
9528 // IMPORTANT: This routine only works when there is no other flip operation //
9529 // is done after flipnm([a,b]) which attempts to remove an edge [a,b]. //
9530 // //
9531 // 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
9532 // [a,b] before flipnm([a,b]). 'nn' (< n) is the value returned by flipnm. //
9533 // If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
9534 // are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
9535 // b] and its initial Star([a,b]). If 'nn >= 3' edge [a,b] still exists in //
9536 // current mesh and 'nn' is the current number of tets in Star([a,b]). //
9537 // //
9538 // Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a //
9539 // flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet //
9540 // 'abtets[t-1]', where '0 <= t <= i'. These information can be used to //
9541 // undo the flips performed in flipnm([a,b]) or to collect new tets created //
9542 // by the flipnm([a,b]) operation. //
9543 // //
9544 // Default, this routine only walks through the flips and frees the spaces //
9545 // allocated during the flipnm([a,b]) operation. //
9546 // //
9547 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
9548 // in flipnm([a,b]) so that the mesh is returned to its original state //
9549 // before doing the flipnm([a,b]) operation. //
9550 // //
9551 // //
9553 
9554 int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
9555  flipconstraints* fc)
9556 {
9557  triface fliptets[3], flipface;
9558  triface *tmpabtets;
9559  int fliptype;
9560  int edgepivot;
9561  int t, n1;
9562  int i, j;
9563 
9564 
9565  if (nn == 2) {
9566  // The edge [a,b] has been flipped.
9567  // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
9568  // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
9569  if (fc->unflip) {
9570  // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
9571  flip23(abtets, 1, fc);
9572  if (fc->collectnewtets) {
9573  // Pop up new (flipped) tets from the stack.
9574  if (abedgepivot == 0) {
9575  // Two new tets were collected.
9576  cavetetlist->objects -= 2;
9577  } else {
9578  // Only one of the two new tets was collected.
9579  cavetetlist->objects -= 1;
9580  }
9581  }
9582  }
9583  // The initial size of Star(ab) is 3.
9584  nn++;
9585  }
9586 
9587  // Walk through the performed flips.
9588  for (i = nn; i < n; i++) {
9589  // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
9590  // At the end of this step, the size of the Star([a,b]) is 'i+1'.
9591  // The sizes of the Link([a,b]) are the same.
9592  fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
9593  if (fliptype == 1) {
9594  // It was a 2-to-3 flip: [a,b,c]->[e,d].
9595  t = (abtets[i].ver >> 6);
9596  if (fc->unflip) {
9597  if (b->verbose > 2) {
9598  printf(" Recover a 2-to-3 flip at f[%d].\n", t);
9599  }
9600  // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
9601  // it is created by a 2-to-3 flip [a,b,c] => [e,d].
9602  fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
9603  eprevself(fliptets[0]);
9604  esymself(fliptets[0]);
9605  enextself(fliptets[0]); // [e,d,a,b]
9606  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
9607  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
9608  // Do a 3-to-2 flip: [e,d] => [a,b,c].
9609  // NOTE: hull tets may be invloved.
9610  flip32(fliptets, 1, fc);
9611  // Expand the array 'abtets', maintain the original order.
9612  // The new array length is (i+1).
9613  for (j = i - 1; j >= t; j--) {
9614  abtets[j + 1] = abtets[j]; // Downshift
9615  }
9616  // The tet abtets[(t-1)%i] is deleted. Insert the two new tets
9617  // 'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
9618  // the (t-1)-th and t-th entries, respectively.
9619  esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
9620  abtets[t] = fliptets[0]; // [a,b,c,d]
9621  if (fc->collectnewtets) {
9622  // Pop up two (flipped) tets from the stack.
9623  cavetetlist->objects -= 2;
9624  }
9625  }
9626  } else if (fliptype == 2) {
9627  tmpabtets = (triface *) (abtets[i].tet);
9628  n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
9629  edgepivot = (abtets[i].ver & 3);
9630  t = ((abtets[i].ver >> 6) & 8191);
9631  if (fc->unflip) {
9632  if (b->verbose > 2) {
9633  printf(" Recover a %d-to-m flip at e[%d] of f[%d].\n", n1,
9634  edgepivot, t);
9635  }
9636  // Recover the flipped edge ([c,b] or [a,c]).
9637  // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
9638  // the flipping of edge [c,b] or [a,c]. It must still exist in
9639  // Star(ab). Use it to recover the flipped edge.
9640  if (edgepivot == 1) {
9641  // The flip edge is [c,b].
9642  tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
9643  eprevself(tmpabtets[0]);
9644  esymself(tmpabtets[0]);
9645  eprevself(tmpabtets[0]); // [d,a,e,b]
9646  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
9647  } else {
9648  // The flip edge is [a,c].
9649  tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
9650  enextself(tmpabtets[1]);
9651  esymself(tmpabtets[1]);
9652  enextself(tmpabtets[1]); // [b,d,e,a]
9653  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
9654  } // if (edgepivot == 2)
9655 
9656  // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
9657  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9658 
9659  // Insert the two recovered tets into the original Star(ab).
9660  for (j = i - 1; j >= t; j--) {
9661  abtets[j + 1] = abtets[j]; // Downshift
9662  }
9663  if (edgepivot == 1) {
9664  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
9665  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
9666  // tmpabtets[2] is [c,b,e,d]
9667  fliptets[0] = tmpabtets[1];
9668  enextself(fliptets[0]);
9669  esymself(fliptets[0]); // [a,b,e,c]
9670  fliptets[1] = tmpabtets[0];
9671  esymself(fliptets[1]);
9672  eprevself(fliptets[1]); // [a,b,c,d]
9673  } else {
9674  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
9675  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
9676  // tmpabtets[2] is [a,c,e,d]
9677  fliptets[0] = tmpabtets[1];
9678  eprevself(fliptets[0]);
9679  esymself(fliptets[0]); // [a,b,e,c]
9680  fliptets[1] = tmpabtets[0];
9681  esymself(fliptets[1]);
9682  enextself(fliptets[1]); // [a,b,c,d]
9683  } // edgepivot == 2
9684  // Insert the two recovered tets into Star(ab).
9685  abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
9686  abtets[t] = fliptets[1];
9687  }
9688  else {
9689  // Only free the spaces.
9690  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9691  } // if (!unflip)
9692  if (b->verbose > 2) {
9693  printf(" Release %d spaces at f[%d].\n", n1, i);
9694  }
9695  delete [] tmpabtets;
9696  }
9697  } // i
9698 
9699  return 1;
9700 }
9701 
9703 // //
9704 // insertpoint() Insert a point into current tetrahedralization. //
9705 // //
9706 // The Bowyer-Watson (B-W) algorithm is used to add a new point p into the //
9707 // tetrahedralization T. It first finds a "cavity", denoted as C, in T, C //
9708 // consists of tetrahedra in T that "conflict" with p. If T is a Delaunay //
9709 // tetrahedralization, then all boundary faces (triangles) of C are visible //
9710 // by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
9711 // tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
9712 // C and p. If T is not a DT, then C may be not star-shaped. It must be //
9713 // modified so that it becomes star-shaped. //
9714 // //
9716 
9717 int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
9718  face *splitseg, insertvertexflags *ivf)
9719 {
9720  arraypool *swaplist;
9721  triface *cavetet, spintet, neightet, neineitet, *parytet;
9722  triface oldtet, newtet, newneitet;
9723  face checksh, neighsh, *parysh;
9724  face checkseg, *paryseg;
9725  point *pts, pa, pb, pc, *parypt;
9726  enum locateresult loc = OUTSIDE;
9727  REAL sign, ori;
9728  REAL attrib, volume;
9729  bool enqflag;
9730  int t1ver;
9731  int i, j, k, s;
9732 
9733  if (b->verbose > 2) {
9734  printf(" Insert point %d\n", pointmark(insertpt));
9735  }
9736 
9737  // Locate the point.
9738  if (searchtet->tet != NULL) {
9739  loc = (enum locateresult) ivf->iloc;
9740  }
9741 
9742  if (loc == OUTSIDE) {
9743  if (searchtet->tet == NULL) {
9744  if (!b->weighted) {
9745  randomsample(insertpt, searchtet);
9746  } else {
9747  // Weighted DT. There may exist dangling vertex.
9748  *searchtet = recenttet;
9749  }
9750  }
9751  // Locate the point.
9752  loc = locate(insertpt, searchtet);
9753  }
9754 
9755  ivf->iloc = (int) loc; // The return value.
9756 
9757  if (b->weighted) {
9758  if (loc != OUTSIDE) {
9759  // Check if this vertex is regular.
9760  pts = (point *) searchtet->tet;
9761  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9762  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9763  insertpt[3]);
9764  if (sign > 0) {
9765  // This new vertex lies above the lower hull. Do not insert it.
9766  ivf->iloc = (int) NONREGULAR;
9767  return 0;
9768  }
9769  }
9770  }
9771 
9772  // Create the initial cavity C(p) which contains all tetrahedra that
9773  // intersect p. It may include 1, 2, or n tetrahedra.
9774  // If p lies on a segment or subface, also create the initial sub-cavity
9775  // sC(p) which contains all subfaces (and segment) which intersect p.
9776 
9777  if (loc == OUTSIDE) {
9778  flip14count++;
9779  // The current hull will be enlarged.
9780  // Add four adjacent boundary tets into list.
9781  for (i = 0; i < 4; i++) {
9782  decode(searchtet->tet[i], neightet);
9783  neightet.ver = epivot[neightet.ver];
9784  cavebdrylist->newindex((void **) &parytet);
9785  *parytet = neightet;
9786  }
9787  infect(*searchtet);
9788  caveoldtetlist->newindex((void **) &parytet);
9789  *parytet = *searchtet;
9790  } else if (loc == INTETRAHEDRON) {
9791  flip14count++;
9792  // Add four adjacent boundary tets into list.
9793  for (i = 0; i < 4; i++) {
9794  decode(searchtet->tet[i], neightet);
9795  neightet.ver = epivot[neightet.ver];
9796  cavebdrylist->newindex((void **) &parytet);
9797  *parytet = neightet;
9798  }
9799  infect(*searchtet);
9800  caveoldtetlist->newindex((void **) &parytet);
9801  *parytet = *searchtet;
9802  } else if (loc == ONFACE) {
9803  flip26count++;
9804  // Add six adjacent boundary tets into list.
9805  j = (searchtet->ver & 3); // The current face number.
9806  for (i = 1; i < 4; i++) {
9807  decode(searchtet->tet[(j + i) % 4], neightet);
9808  neightet.ver = epivot[neightet.ver];
9809  cavebdrylist->newindex((void **) &parytet);
9810  *parytet = neightet;
9811  }
9812  decode(searchtet->tet[j], spintet);
9813  j = (spintet.ver & 3); // The current face number.
9814  for (i = 1; i < 4; i++) {
9815  decode(spintet.tet[(j + i) % 4], neightet);
9816  neightet.ver = epivot[neightet.ver];
9817  cavebdrylist->newindex((void **) &parytet);
9818  *parytet = neightet;
9819  }
9820  infect(spintet);
9821  caveoldtetlist->newindex((void **) &parytet);
9822  *parytet = spintet;
9823  infect(*searchtet);
9824  caveoldtetlist->newindex((void **) &parytet);
9825  *parytet = *searchtet;
9826 
9827  if (ivf->splitbdflag) {
9828  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9829  // Create the initial sub-cavity sC(p).
9830  smarktest(*splitsh);
9831  caveshlist->newindex((void **) &parysh);
9832  *parysh = *splitsh;
9833  }
9834  } // if (splitbdflag)
9835  } else if (loc == ONEDGE) {
9836  flipn2ncount++;
9837  // Add all adjacent boundary tets into list.
9838  spintet = *searchtet;
9839  while (1) {
9840  eorgoppo(spintet, neightet);
9841  decode(neightet.tet[neightet.ver & 3], neightet);
9842  neightet.ver = epivot[neightet.ver];
9843  cavebdrylist->newindex((void **) &parytet);
9844  *parytet = neightet;
9845  edestoppo(spintet, neightet);
9846  decode(neightet.tet[neightet.ver & 3], neightet);
9847  neightet.ver = epivot[neightet.ver];
9848  cavebdrylist->newindex((void **) &parytet);
9849  *parytet = neightet;
9850  infect(spintet);
9851  caveoldtetlist->newindex((void **) &parytet);
9852  *parytet = spintet;
9853  fnextself(spintet);
9854  if (spintet.tet == searchtet->tet) break;
9855  } // while (1)
9856 
9857  if (ivf->splitbdflag) {
9858  // Create the initial sub-cavity sC(p).
9859  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9860  smarktest(*splitseg);
9861  splitseg->shver = 0;
9862  spivot(*splitseg, *splitsh);
9863  }
9864  if (splitsh != NULL) {
9865  if (splitsh->sh != NULL) {
9866  // Collect all subfaces share at this edge.
9867  pa = sorg(*splitsh);
9868  neighsh = *splitsh;
9869  while (1) {
9870  // Adjust the origin of its edge to be 'pa'.
9871  if (sorg(neighsh) != pa) {
9872  sesymself(neighsh);
9873  }
9874  // Add this face into list (in B-W cavity).
9875  smarktest(neighsh);
9876  caveshlist->newindex((void **) &parysh);
9877  *parysh = neighsh;
9878  // Add this face into face-at-splitedge list.
9879  cavesegshlist->newindex((void **) &parysh);
9880  *parysh = neighsh;
9881  // Go to the next face at the edge.
9882  spivotself(neighsh);
9883  // Stop if all faces at the edge have been visited.
9884  if (neighsh.sh == splitsh->sh) break;
9885  if (neighsh.sh == NULL) break;
9886  } // while (1)
9887  } // if (not a dangling segment)
9888  }
9889  } // if (splitbdflag)
9890  } else if (loc == INSTAR) {
9891  // We assume that all tets in the star are given in 'caveoldtetlist',
9892  // and they are all infected.
9893  // Collect the boundary faces of the star.
9894  for (i = 0; i < caveoldtetlist->objects; i++) {
9895  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9896  // Check its 4 neighbor tets.
9897  for (j = 0; j < 4; j++) {
9898  decode(cavetet->tet[j], neightet);
9899  if (!infected(neightet)) {
9900  // It's a boundary face.
9901  neightet.ver = epivot[neightet.ver];
9902  cavebdrylist->newindex((void **) &parytet);
9903  *parytet = neightet;
9904  }
9905  }
9906  }
9907  } else if (loc == ONVERTEX) {
9908  // The point already exist. Do nothing and return.
9909  return 0;
9910  }
9911 
9912 
9913  if (ivf->assignmeshsize) {
9914  // Assign mesh size for the new point.
9915  if (bgm != NULL) {
9916  // Interpolate the mesh size from the background mesh.
9917  bgm->decode(point2bgmtet(org(*searchtet)), neightet);
9918  int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
9919  if (bgmloc != (int) OUTSIDE) {
9920  insertpt[pointmtrindex] =
9921  bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
9922  setpoint2bgmtet(insertpt, bgm->encode(neightet));
9923  }
9924  } else {
9925  insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
9926  }
9927  } // if (assignmeshsize)
9928 
9929  if (ivf->bowywat) {
9930  // Update the cavity C(p) using the Bowyer-Watson algorithm.
9931  swaplist = cavetetlist;
9932  cavetetlist = cavebdrylist;
9933  cavebdrylist = swaplist;
9934  for (i = 0; i < cavetetlist->objects; i++) {
9935  // 'cavetet' is an adjacent tet at outside of the cavity.
9936  cavetet = (triface *) fastlookup(cavetetlist, i);
9937  // The tet may be tested and included in the (enlarged) cavity.
9938  if (!infected(*cavetet)) {
9939  // Check for two possible cases for this tet:
9940  // (1) It is a cavity tet, or
9941  // (2) it is a cavity boundary face.
9942  enqflag = false;
9943  if (!marktested(*cavetet)) {
9944  // Do Delaunay (in-sphere) test.
9945  pts = (point *) cavetet->tet;
9946  if (pts[7] != dummypoint) {
9947  // A volume tet. Operate on it.
9948  if (b->weighted) {
9949  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9950  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9951  insertpt[3]);
9952  } else {
9953  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
9954  }
9955  enqflag = (sign < 0.0);
9956  } else {
9957  if (!nonconvex) {
9958  // Test if this hull face is visible by the new point.
9959  ori = orient3d(pts[4], pts[5], pts[6], insertpt);
9960  if (ori < 0) {
9961  // A visible hull face.
9962  // Include it in the cavity. The convex hull will be enlarged.
9963  enqflag = true;
9964  } else if (ori == 0.0) {
9965  // A coplanar hull face. We need to test if this hull face is
9966  // Delaunay or not. We test if the adjacent tet (not faked)
9967  // of this hull face is Delaunay or not.
9968  decode(cavetet->tet[3], neineitet);
9969  if (!infected(neineitet)) {
9970  if (!marktested(neineitet)) {
9971  // Do Delaunay test on this tet.
9972  pts = (point *) neineitet.tet;
9973  if (b->weighted) {
9974  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9975  pts[4][3], pts[5][3], pts[6][3],
9976  pts[7][3], insertpt[3]);
9977  } else {
9978  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9979  }
9980  enqflag = (sign < 0.0);
9981  }
9982  } else {
9983  // The adjacent tet is non-Delaunay. The hull face is non-
9984  // Delaunay as well. Include it in the cavity.
9985  enqflag = true;
9986  } // if (!infected(neineitet))
9987  } // if (ori == 0.0)
9988  } else {
9989  // A hull face (must be a subface).
9990  // We FIRST include it in the initial cavity if the adjacent tet
9991  // (not faked) of this hull face is not Delaunay wrt p.
9992  // Whether it belongs to the final cavity will be determined
9993  // during the validation process. 'validflag'.
9994  decode(cavetet->tet[3], neineitet);
9995  if (!infected(neineitet)) {
9996  if (!marktested(neineitet)) {
9997  // Do Delaunay test on this tet.
9998  pts = (point *) neineitet.tet;
9999  if (b->weighted) {
10000  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
10001  pts[4][3], pts[5][3], pts[6][3],
10002  pts[7][3], insertpt[3]);
10003  } else {
10004  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
10005  }
10006  enqflag = (sign < 0.0);
10007  }
10008  } else {
10009  // The adjacent tet is non-Delaunay. The hull face is non-
10010  // Delaunay as well. Include it in the cavity.
10011  enqflag = true;
10012  } // if (infected(neineitet))
10013  } // if (nonconvex)
10014  } // if (pts[7] != dummypoint)
10015  marktest(*cavetet); // Only test it once.
10016  } // if (!marktested(*cavetet))
10017 
10018  if (enqflag) {
10019  // Found a tet in the cavity. Put other three faces in check list.
10020  k = (cavetet->ver & 3); // The current face number
10021  for (j = 1; j < 4; j++) {
10022  decode(cavetet->tet[(j + k) % 4], neightet);
10023  cavetetlist->newindex((void **) &parytet);
10024  *parytet = neightet;
10025  }
10026  infect(*cavetet);
10027  caveoldtetlist->newindex((void **) &parytet);
10028  *parytet = *cavetet;
10029  } else {
10030  // Found a boundary face of the cavity.
10031  cavetet->ver = epivot[cavetet->ver];
10032  cavebdrylist->newindex((void **) &parytet);
10033  *parytet = *cavetet;
10034  }
10035  } // if (!infected(*cavetet))
10036  } // i
10037 
10038  cavetetlist->restart(); // Clear the working list.
10039  } // if (ivf->bowywat)
10040 
10041  if (checksubsegflag) {
10042  // Collect all segments of C(p).
10043  shellface *ssptr;
10044  for (i = 0; i < caveoldtetlist->objects; i++) {
10045  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10046  if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
10047  for (j = 0; j < 6; j++) {
10048  if (ssptr[j]) {
10049  sdecode(ssptr[j], checkseg);
10050  if (!sinfected(checkseg)) {
10051  sinfect(checkseg);
10052  cavetetseglist->newindex((void **) &paryseg);
10053  *paryseg = checkseg;
10054  }
10055  }
10056  } // j
10057  }
10058  } // i
10059  // Uninfect collected segments.
10060  for (i = 0; i < cavetetseglist->objects; i++) {
10061  paryseg = (face *) fastlookup(cavetetseglist, i);
10062  suninfect(*paryseg);
10063  }
10064 
10065  if (ivf->rejflag & 1) {
10066  // Reject this point if it encroaches upon any segment.
10067  face *paryseg1;
10068  for (i = 0; i < cavetetseglist->objects; i++) {
10069  paryseg1 = (face *) fastlookup(cavetetseglist, i);
10070  if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4],
10071  insertpt)) {
10072  encseglist->newindex((void **) &paryseg);
10073  *paryseg = *paryseg1;
10074  }
10075  } // i
10076  if ((ivf->rejflag & 1) && (encseglist->objects > 0)) {
10077  insertpoint_abort(splitseg, ivf);
10078  ivf->iloc = (int) ENCSEGMENT;
10079  return 0;
10080  }
10081  }
10082  } // if (checksubsegflag)
10083 
10084  if (checksubfaceflag) {
10085  // Collect all subfaces of C(p).
10086  shellface *sptr;
10087  for (i = 0; i < caveoldtetlist->objects; i++) {
10088  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10089  if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
10090  for (j = 0; j < 4; j++) {
10091  if (sptr[j]) {
10092  sdecode(sptr[j], checksh);
10093  if (!sinfected(checksh)) {
10094  sinfect(checksh);
10095  cavetetshlist->newindex((void **) &parysh);
10096  *parysh = checksh;
10097  }
10098  }
10099  } // j
10100  }
10101  } // i
10102  // Uninfect collected subfaces.
10103  for (i = 0; i < cavetetshlist->objects; i++) {
10104  parysh = (face *) fastlookup(cavetetshlist, i);
10105  suninfect(*parysh);
10106  }
10107 
10108  if (ivf->rejflag & 2) {
10109  REAL rd, cent[3];
10110  badface *bface;
10111  // Reject this point if it encroaches upon any subface.
10112  for (i = 0; i < cavetetshlist->objects; i++) {
10113  parysh = (face *) fastlookup(cavetetshlist, i);
10114  if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4],
10115  (point) parysh->sh[5], insertpt, cent, &rd)) {
10116  encshlist->newindex((void **) &bface);
10117  bface->ss = *parysh;
10118  bface->forg = (point) parysh->sh[3]; // Not a dad one.
10119  for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
10120  bface->key = rd;
10121  }
10122  }
10123  if (encshlist->objects > 0) {
10124  insertpoint_abort(splitseg, ivf);
10125  ivf->iloc = (int) ENCSUBFACE;
10126  return 0;
10127  }
10128  }
10129  } // if (checksubfaceflag)
10130 
10131  if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
10132  // The vertex lies outside of the domain. And it does not encroach
10133  // upon any boundary segment or subface. Do not insert it.
10134  insertpoint_abort(splitseg, ivf);
10135  return 0;
10136  }
10137 
10138  if (ivf->splitbdflag) {
10139  // The new point locates in surface mesh. Update the sC(p).
10140  // We have already 'smarktested' the subfaces which directly intersect
10141  // with p in 'caveshlist'. From them, we 'smarktest' their neighboring
10142  // subfaces which are included in C(p). Do not across a segment.
10143  for (i = 0; i < caveshlist->objects; i++) {
10144  parysh = (face *) fastlookup(caveshlist, i);
10145  checksh = *parysh;
10146  for (j = 0; j < 3; j++) {
10147  if (!isshsubseg(checksh)) {
10148  spivot(checksh, neighsh);
10149  if (!smarktested(neighsh)) {
10150  stpivot(neighsh, neightet);
10151  if (infected(neightet)) {
10152  fsymself(neightet);
10153  if (infected(neightet)) {
10154  // This subface is inside C(p).
10155  // Check if its diametrical circumsphere encloses 'p'.
10156  // The purpose of this check is to avoid forming invalid
10157  // subcavity in surface mesh.
10158  sign = incircle3d(sorg(neighsh), sdest(neighsh),
10159  sapex(neighsh), insertpt);
10160  if (sign < 0) {
10161  smarktest(neighsh);
10162  caveshlist->newindex((void **) &parysh);
10163  *parysh = neighsh;
10164  }
10165  }
10166  }
10167  }
10168  }
10169  senextself(checksh);
10170  } // j
10171  } // i
10172  } // if (ivf->splitbdflag)
10173 
10174  if (ivf->validflag) {
10175  // Validate C(p) and update it if it is not star-shaped.
10176  int cutcount = 0;
10177 
10178  if (ivf->respectbdflag) {
10179  // The initial cavity may include subfaces which are not on the facets
10180  // being splitting. Find them and make them as boundary of C(p).
10181  // Comment: We have already 'smarktested' the subfaces in sC(p). They
10182  // are completely inside C(p).
10183  for (i = 0; i < cavetetshlist->objects; i++) {
10184  parysh = (face *) fastlookup(cavetetshlist, i);
10185  stpivot(*parysh, neightet);
10186  if (infected(neightet)) {
10187  fsymself(neightet);
10188  if (infected(neightet)) {
10189  // Found a subface inside C(p).
10190  if (!smarktested(*parysh)) {
10191  // It is possible that this face is a boundary subface.
10192  // Check if it is a hull face.
10193  //assert(apex(neightet) != dummypoint);
10194  if (oppo(neightet) != dummypoint) {
10195  fsymself(neightet);
10196  }
10197  if (oppo(neightet) != dummypoint) {
10198  ori = orient3d(org(neightet), dest(neightet), apex(neightet),
10199  insertpt);
10200  if (ori < 0) {
10201  // A visible face, get its neighbor face.
10202  fsymself(neightet);
10203  ori = -ori; // It must be invisible by p.
10204  }
10205  } else {
10206  // A hull tet. It needs to be cut.
10207  ori = 1;
10208  }
10209  // Cut this tet if it is either invisible by or coplanar with p.
10210  if (ori >= 0) {
10211  uninfect(neightet);
10212  unmarktest(neightet);
10213  cutcount++;
10214  neightet.ver = epivot[neightet.ver];
10215  cavebdrylist->newindex((void **) &parytet);
10216  *parytet = neightet;
10217  // Add three new faces to find new boundaries.
10218  for (j = 0; j < 3; j++) {
10219  esym(neightet, neineitet);
10220  neineitet.ver = epivot[neineitet.ver];
10221  cavebdrylist->newindex((void **) &parytet);
10222  *parytet = neineitet;
10223  enextself(neightet);
10224  }
10225  } // if (ori >= 0)
10226  }
10227  }
10228  }
10229  } // i
10230 
10231  // The initial cavity may include segments in its interior. We need to
10232  // Update the cavity so that these segments are on the boundary of
10233  // the cavity.
10234  for (i = 0; i < cavetetseglist->objects; i++) {
10235  paryseg = (face *) fastlookup(cavetetseglist, i);
10236  // Check this segment if it is not a splitting segment.
10237  if (!smarktested(*paryseg)) {
10238  sstpivot1(*paryseg, neightet);
10239  spintet = neightet;
10240  while (1) {
10241  if (!infected(spintet)) break;
10242  fnextself(spintet);
10243  if (spintet.tet == neightet.tet) break;
10244  }
10245  if (infected(spintet)) {
10246  // Find an adjacent tet at this segment such that both faces
10247  // at this segment are not visible by p.
10248  pa = org(neightet);
10249  pb = dest(neightet);
10250  spintet = neightet;
10251  j = 0;
10252  while (1) {
10253  // Check if this face is visible by p.
10254  pc = apex(spintet);
10255  if (pc != dummypoint) {
10256  ori = orient3d(pa, pb, pc, insertpt);
10257  if (ori >= 0) {
10258  // Not visible. Check another face in this tet.
10259  esym(spintet, neineitet);
10260  pc = apex(neineitet);
10261  if (pc != dummypoint) {
10262  ori = orient3d(pb, pa, pc, insertpt);
10263  if (ori >= 0) {
10264  // Not visible. Found this face.
10265  j = 1; // Flag that it is found.
10266  break;
10267  }
10268  }
10269  }
10270  }
10271  fnextself(spintet);
10272  if (spintet.tet == neightet.tet) break;
10273  }
10274  if (j == 0) {
10275  // Not found such a face.
10276  terminatetetgen(this, 2);
10277  }
10278  neightet = spintet;
10279  if (b->verbose > 3) {
10280  printf(" Cut tet (%d, %d, %d, %d)\n",
10281  pointmark(org(neightet)), pointmark(dest(neightet)),
10282  pointmark(apex(neightet)), pointmark(oppo(neightet)));
10283  }
10284  uninfect(neightet);
10285  unmarktest(neightet);
10286  cutcount++;
10287  neightet.ver = epivot[neightet.ver];
10288  cavebdrylist->newindex((void **) &parytet);
10289  *parytet = neightet;
10290  // Add three new faces to find new boundaries.
10291  for (j = 0; j < 3; j++) {
10292  esym(neightet, neineitet);
10293  neineitet.ver = epivot[neineitet.ver];
10294  cavebdrylist->newindex((void **) &parytet);
10295  *parytet = neineitet;
10296  enextself(neightet);
10297  }
10298  }
10299  }
10300  } // i
10301  } // if (ivf->respectbdflag)
10302 
10303  // Update the cavity by removing invisible faces until it is star-shaped.
10304  for (i = 0; i < cavebdrylist->objects; i++) {
10305  cavetet = (triface *) fastlookup(cavebdrylist, i);
10306  // 'cavetet' is an exterior tet adjacent to the cavity.
10307  // Check if its neighbor is inside C(p).
10308  fsym(*cavetet, neightet);
10309  if (infected(neightet)) {
10310  if (apex(*cavetet) != dummypoint) {
10311  // It is a cavity boundary face. Check its visibility.
10312  if (oppo(neightet) != dummypoint) {
10313  // Check if this face is visible by the new point.
10314  if (issubface(neightet)) {
10315  // We should only create a new tet that has a reasonable volume.
10316  // Re-use 'volume' and 'attrib'.
10317  pa = org(*cavetet);
10318  pb = dest(*cavetet);
10319  pc = apex(*cavetet);
10320  volume = orient3dfast(pa, pb, pc, insertpt);
10321  attrib = distance(pa, pb) * distance(pb, pc) * distance(pc, pa);
10322  if ((fabs(volume) / attrib) < b->epsilon) {
10323  ori = 0.0;
10324  } else {
10325  ori = orient3d(pa, pb, pc, insertpt);
10326  }
10327  } else {
10328  ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
10329  insertpt);
10330  }
10331  enqflag = (ori > 0);
10332  // Comment: if ori == 0 (coplanar case), we also cut the tet.
10333  } else {
10334  // It is a hull face. And its adjacent tet (at inside of the
10335  // domain) has been cut from the cavity. Cut it as well.
10336  //assert(nonconvex);
10337  enqflag = false;
10338  }
10339  } else {
10340  enqflag = true; // A hull edge.
10341  }
10342  if (enqflag) {
10343  // This face is valid, save it.
10344  cavetetlist->newindex((void **) &parytet);
10345  *parytet = *cavetet;
10346  } else {
10347  uninfect(neightet);
10348  unmarktest(neightet);
10349  cutcount++;
10350  // Add three new faces to find new boundaries.
10351  for (j = 0; j < 3; j++) {
10352  esym(neightet, neineitet);
10353  neineitet.ver = epivot[neineitet.ver];
10354  cavebdrylist->newindex((void **) &parytet);
10355  *parytet = neineitet;
10356  enextself(neightet);
10357  }
10358  // 'cavetet' is not on the cavity boundary anymore.
10359  unmarktest(*cavetet);
10360  }
10361  } else {
10362  // 'cavetet' is not on the cavity boundary anymore.
10363  unmarktest(*cavetet);
10364  }
10365  } // i
10366 
10367  if (cutcount > 0) {
10368  // The cavity has been updated.
10369  // Update the cavity boundary faces.
10370  cavebdrylist->restart();
10371  for (i = 0; i < cavetetlist->objects; i++) {
10372  cavetet = (triface *) fastlookup(cavetetlist, i);
10373  // 'cavetet' was an exterior tet adjacent to the cavity.
10374  fsym(*cavetet, neightet);
10375  if (infected(neightet)) {
10376  // It is a cavity boundary face.
10377  cavebdrylist->newindex((void **) &parytet);
10378  *parytet = *cavetet;
10379  } else {
10380  // Not a cavity boundary face.
10381  unmarktest(*cavetet);
10382  }
10383  }
10384 
10385  // Update the list of old tets.
10386  cavetetlist->restart();
10387  for (i = 0; i < caveoldtetlist->objects; i++) {
10388  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10389  if (infected(*cavetet)) {
10390  cavetetlist->newindex((void **) &parytet);
10391  *parytet = *cavetet;
10392  }
10393  }
10394  // Swap 'cavetetlist' and 'caveoldtetlist'.
10395  swaplist = caveoldtetlist;
10396  caveoldtetlist = cavetetlist;
10397  cavetetlist = swaplist;
10398 
10399  // The cavity should contain at least one tet.
10400  if (caveoldtetlist->objects == 0l) {
10401  insertpoint_abort(splitseg, ivf);
10402  ivf->iloc = (int) BADELEMENT;
10403  return 0;
10404  }
10405 
10406  if (ivf->splitbdflag) {
10407  int cutshcount = 0;
10408  // Update the sub-cavity sC(p).
10409  for (i = 0; i < caveshlist->objects; i++) {
10410  parysh = (face *) fastlookup(caveshlist, i);
10411  if (smarktested(*parysh)) {
10412  enqflag = false;
10413  stpivot(*parysh, neightet);
10414  if (infected(neightet)) {
10415  fsymself(neightet);
10416  if (infected(neightet)) {
10417  enqflag = true;
10418  }
10419  }
10420  if (!enqflag) {
10421  sunmarktest(*parysh);
10422  // Use the last entry of this array to fill this entry.
10423  j = caveshlist->objects - 1;
10424  checksh = * (face *) fastlookup(caveshlist, j);
10425  *parysh = checksh;
10426  cutshcount++;
10427  caveshlist->objects--; // The list is shrinked.
10428  i--;
10429  }
10430  }
10431  }
10432 
10433  if (cutshcount > 0) {
10434  i = 0; // Count the number of invalid subfaces/segments.
10435  // Valid the updated sub-cavity sC(p).
10436  if (loc == ONFACE) {
10437  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
10438  // The to-be split subface should be in sC(p).
10439  if (!smarktested(*splitsh)) i++;
10440  }
10441  } else if (loc == ONEDGE) {
10442  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10443  // The to-be split segment should be in sC(p).
10444  if (!smarktested(*splitseg)) i++;
10445  }
10446  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
10447  // All subfaces at this edge should be in sC(p).
10448  pa = sorg(*splitsh);
10449  neighsh = *splitsh;
10450  while (1) {
10451  // Adjust the origin of its edge to be 'pa'.
10452  if (sorg(neighsh) != pa) {
10453  sesymself(neighsh);
10454  }
10455  // Add this face into list (in B-W cavity).
10456  if (!smarktested(neighsh)) i++;
10457  // Go to the next face at the edge.
10458  spivotself(neighsh);
10459  // Stop if all faces at the edge have been visited.
10460  if (neighsh.sh == splitsh->sh) break;
10461  if (neighsh.sh == NULL) break;
10462  } // while (1)
10463  }
10464  }
10465 
10466  if (i > 0) {
10467  // The updated sC(p) is invalid. Do not insert this vertex.
10468  insertpoint_abort(splitseg, ivf);
10469  ivf->iloc = (int) BADELEMENT;
10470  return 0;
10471  }
10472  } // if (cutshcount > 0)
10473  } // if (ivf->splitbdflag)
10474  } // if (cutcount > 0)
10475 
10476  } // if (ivf->validflag)
10477 
10478  if (ivf->refineflag) {
10479  // The new point is inserted by Delaunay refinement, i.e., it is the
10480  // circumcenter of a tetrahedron, or a subface, or a segment.
10481  // Do not insert this point if the tetrahedron, or subface, or segment
10482  // is not inside the final cavity.
10483  if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
10484  ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
10485  insertpoint_abort(splitseg, ivf);
10486  ivf->iloc = (int) BADELEMENT;
10487  return 0;
10488  }
10489  } // if (ivf->refineflag)
10490 
10491  if (b->plc && (loc != INSTAR)) {
10492  // Reject the new point if it lies too close to an existing point (b->plc),
10493  // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
10494  // Collect the list of vertices of the initial cavity.
10495  if (loc == OUTSIDE) {
10496  pts = (point *) &(searchtet->tet[4]);
10497  for (i = 0; i < 3; i++) {
10498  cavetetvertlist->newindex((void **) &parypt);
10499  *parypt = pts[i];
10500  }
10501  } else if (loc == INTETRAHEDRON) {
10502  pts = (point *) &(searchtet->tet[4]);
10503  for (i = 0; i < 4; i++) {
10504  cavetetvertlist->newindex((void **) &parypt);
10505  *parypt = pts[i];
10506  }
10507  } else if (loc == ONFACE) {
10508  pts = (point *) &(searchtet->tet[4]);
10509  for (i = 0; i < 3; i++) {
10510  cavetetvertlist->newindex((void **) &parypt);
10511  *parypt = pts[i];
10512  }
10513  if (pts[3] != dummypoint) {
10514  cavetetvertlist->newindex((void **) &parypt);
10515  *parypt = pts[3];
10516  }
10517  fsym(*searchtet, spintet);
10518  if (oppo(spintet) != dummypoint) {
10519  cavetetvertlist->newindex((void **) &parypt);
10520  *parypt = oppo(spintet);
10521  }
10522  } else if (loc == ONEDGE) {
10523  spintet = *searchtet;
10524  cavetetvertlist->newindex((void **) &parypt);
10525  *parypt = org(spintet);
10526  cavetetvertlist->newindex((void **) &parypt);
10527  *parypt = dest(spintet);
10528  while (1) {
10529  if (apex(spintet) != dummypoint) {
10530  cavetetvertlist->newindex((void **) &parypt);
10531  *parypt = apex(spintet);
10532  }
10533  fnextself(spintet);
10534  if (spintet.tet == searchtet->tet) break;
10535  }
10536  }
10537 
10538  int rejptflag = (ivf->rejflag & 4);
10539  REAL rd;
10540  pts = NULL;
10541 
10542  for (i = 0; i < cavetetvertlist->objects; i++) {
10543  parypt = (point *) fastlookup(cavetetvertlist, i);
10544  rd = distance(*parypt, insertpt);
10545  // Is the point very close to an existing point?
10546  if (rd < minedgelength) {
10547  pts = parypt;
10548  loc = NEARVERTEX;
10549  break;
10550  }
10551  if (rejptflag) {
10552  // Is the point encroaches upon an existing point?
10553  if (rd < (0.5 * (*parypt)[pointmtrindex])) {
10554  pts = parypt;
10555  loc = ENCVERTEX;
10556  break;
10557  }
10558  }
10559  }
10560  cavetetvertlist->restart(); // Clear the work list.
10561 
10562  if (pts != NULL) {
10563  // The point is either too close to an existing vertex (NEARVERTEX)
10564  // or encroaches upon (inside the protecting ball) of that vertex.
10565  if (loc == NEARVERTEX) {
10566  if (!issteinerpoint(insertpt) && b->nomergevertex) { // -M0/1 option.
10567  // 'insertpt' is an input vertex.
10568  // In this case, we still insert this vertex. Issue a warning.
10569  if (!b->quiet) {
10570  printf("Warning: Two points, %d and %d, are very close.\n",
10571  pointmark(insertpt), pointmark(*pts));
10572  printf(" Creating a very short edge (len = %g) (< %g).\n",
10573  rd, minedgelength);
10574  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
10575  b->epsilon);
10576  printf(" to avoid this warning.\n");
10577  }
10578  } else {
10579  point2tetorg(*pts, *searchtet);
10580  insertpoint_abort(splitseg, ivf);
10581  ivf->iloc = (int) loc;
10582  return 0;
10583  }
10584  } else { // loc == ENCVERTEX
10585  // The point lies inside the protection ball.
10586  point2tetorg(*pts, *searchtet);
10587  insertpoint_abort(splitseg, ivf);
10588  ivf->iloc = (int) loc;
10589  return 0;
10590  }
10591  }
10592  } // if (b->plc && (loc != INSTAR))
10593 
10594  if (b->weighted || ivf->cdtflag || ivf->smlenflag
10595  ) {
10596  // There may be other vertices inside C(p). We need to find them.
10597  // Collect all vertices of C(p).
10598  for (i = 0; i < caveoldtetlist->objects; i++) {
10599  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10600  //assert(infected(*cavetet));
10601  pts = (point *) &(cavetet->tet[4]);
10602  for (j = 0; j < 4; j++) {
10603  if (pts[j] != dummypoint) {
10604  if (!pinfected(pts[j])) {
10605  pinfect(pts[j]);
10606  cavetetvertlist->newindex((void **) &parypt);
10607  *parypt = pts[j];
10608  }
10609  }
10610  } // j
10611  } // i
10612  // Uninfect all collected (cavity) vertices.
10613  for (i = 0; i < cavetetvertlist->objects; i++) {
10614  parypt = (point *) fastlookup(cavetetvertlist, i);
10615  puninfect(*parypt);
10616  }
10617  if (ivf->smlenflag) {
10618  REAL len;
10619  // Get the length of the shortest edge connecting to 'newpt'.
10620  parypt = (point *) fastlookup(cavetetvertlist, 0);
10621  ivf->smlen = distance(*parypt, insertpt);
10622  ivf->parentpt = *parypt;
10623  for (i = 1; i < cavetetvertlist->objects; i++) {
10624  parypt = (point *) fastlookup(cavetetvertlist, i);
10625  len = distance(*parypt, insertpt);
10626  if (len < ivf->smlen) {
10627  ivf->smlen = len;
10628  ivf->parentpt = *parypt;
10629  }
10630  }
10631  }
10632  }
10633 
10634 
10635  if (ivf->cdtflag) {
10636  // Unmark tets.
10637  for (i = 0; i < caveoldtetlist->objects; i++) {
10638  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10639  unmarktest(*cavetet);
10640  }
10641  for (i = 0; i < cavebdrylist->objects; i++) {
10642  cavetet = (triface *) fastlookup(cavebdrylist, i);
10643  unmarktest(*cavetet);
10644  }
10645  // Clean up arrays which are not needed.
10646  cavetetlist->restart();
10647  if (checksubsegflag) {
10648  cavetetseglist->restart();
10649  }
10650  if (checksubfaceflag) {
10651  cavetetshlist->restart();
10652  }
10653  return 1;
10654  }
10655 
10656  // Before re-mesh C(p). Process the segments and subfaces which are on the
10657  // boundary of C(p). Make sure that each such segment or subface is
10658  // connecting to a tet outside C(p). So we can re-connect them to the
10659  // new tets inside the C(p) later.
10660 
10661  if (checksubsegflag) {
10662  for (i = 0; i < cavetetseglist->objects; i++) {
10663  paryseg = (face *) fastlookup(cavetetseglist, i);
10664  // Operate on it if it is not the splitting segment, i.e., in sC(p).
10665  if (!smarktested(*paryseg)) {
10666  // Check if the segment is inside the cavity.
10667  // 'j' counts the num of adjacent tets of this seg.
10668  // 'k' counts the num of adjacent tets which are 'sinfected'.
10669  j = k = 0;
10670  sstpivot1(*paryseg, neightet);
10671  spintet = neightet;
10672  while (1) {
10673  j++;
10674  if (!infected(spintet)) {
10675  neineitet = spintet; // An outer tet. Remember it.
10676  } else {
10677  k++; // An in tet.
10678  }
10679  fnextself(spintet);
10680  if (spintet.tet == neightet.tet) break;
10681  }
10682  // assert(j > 0);
10683  if (k == 0) {
10684  // The segment is not connect to C(p) anymore. Remove it by
10685  // Replacing it by the last entry of this list.
10686  s = cavetetseglist->objects - 1;
10687  checkseg = * (face *) fastlookup(cavetetseglist, s);
10688  *paryseg = checkseg;
10689  cavetetseglist->objects--;
10690  i--;
10691  } else if (k < j) {
10692  // The segment is on the boundary of C(p).
10693  sstbond1(*paryseg, neineitet);
10694  } else { // k == j
10695  // The segment is inside C(p).
10696  if (!ivf->splitbdflag) {
10697  checkseg = *paryseg;
10698  sinfect(checkseg); // Flag it as an interior segment.
10699  caveencseglist->newindex((void **) &paryseg);
10700  *paryseg = checkseg;
10701  } else {
10702  //assert(0); // Not possible.
10703  terminatetetgen(this, 2);
10704  }
10705  }
10706  } else {
10707  // assert(smarktested(*paryseg));
10708  // Flag it as an interior segment. Do not queue it, since it will
10709  // be deleted after the segment splitting.
10710  sinfect(*paryseg);
10711  }
10712  } // i
10713  } // if (checksubsegflag)
10714 
10715  if (checksubfaceflag) {
10716  for (i = 0; i < cavetetshlist->objects; i++) {
10717  parysh = (face *) fastlookup(cavetetshlist, i);
10718  // Operate on it if it is not inside the sub-cavity sC(p).
10719  if (!smarktested(*parysh)) {
10720  // Check if this subface is inside the cavity.
10721  k = 0;
10722  for (j = 0; j < 2; j++) {
10723  stpivot(*parysh, neightet);
10724  if (!infected(neightet)) {
10725  checksh = *parysh; // Remember this side.
10726  } else {
10727  k++;
10728  }
10729  sesymself(*parysh);
10730  }
10731  if (k == 0) {
10732  // The subface is not connected to C(p). Remove it.
10733  s = cavetetshlist->objects - 1;
10734  checksh = * (face *) fastlookup(cavetetshlist, s);
10735  *parysh = checksh;
10736  cavetetshlist->objects--;
10737  i--;
10738  } else if (k == 1) {
10739  // This side is the outer boundary of C(p).
10740  *parysh = checksh;
10741  } else { // k == 2
10742  if (!ivf->splitbdflag) {
10743  checksh = *parysh;
10744  sinfect(checksh); // Flag it.
10745  caveencshlist->newindex((void **) &parysh);
10746  *parysh = checksh;
10747  } else {
10748  //assert(0); // Not possible.
10749  terminatetetgen(this, 2);
10750  }
10751  }
10752  } else {
10753  // assert(smarktested(*parysh));
10754  // Flag it as an interior subface. Do not queue it. It will be
10755  // deleted after the facet point insertion.
10756  sinfect(*parysh);
10757  }
10758  } // i
10759  } // if (checksubfaceflag)
10760 
10761  // Create new tetrahedra to fill the cavity.
10762 
10763  for (i = 0; i < cavebdrylist->objects; i++) {
10764  cavetet = (triface *) fastlookup(cavebdrylist, i);
10765  neightet = *cavetet;
10766  unmarktest(neightet); // Unmark it.
10767  // Get the oldtet (inside the cavity).
10768  fsym(neightet, oldtet);
10769  if (apex(neightet) != dummypoint) {
10770  // Create a new tet in the cavity.
10771  maketetrahedron(&newtet);
10772  setorg(newtet, dest(neightet));
10773  setdest(newtet, org(neightet));
10774  setapex(newtet, apex(neightet));
10775  setoppo(newtet, insertpt);
10776  } else {
10777  // Create a new hull tet.
10778  hullsize++;
10779  maketetrahedron(&newtet);
10780  setorg(newtet, org(neightet));
10781  setdest(newtet, dest(neightet));
10782  setapex(newtet, insertpt);
10783  setoppo(newtet, dummypoint); // It must opposite to face 3.
10784  // Adjust back to the cavity bounday face.
10785  esymself(newtet);
10786  }
10787  // The new tet inherits attribtes from the old tet.
10788  for (j = 0; j < numelemattrib; j++) {
10789  attrib = elemattribute(oldtet.tet, j);
10790  setelemattribute(newtet.tet, j, attrib);
10791  }
10792  if (b->varvolume) {
10793  volume = volumebound(oldtet.tet);
10794  setvolumebound(newtet.tet, volume);
10795  }
10796  // Connect newtet <==> neightet, this also disconnect the old bond.
10797  bond(newtet, neightet);
10798  // oldtet still connects to neightet.
10799  *cavetet = oldtet; // *cavetet = newtet;
10800  } // i
10801 
10802  // Set a handle for speeding point location.
10803  recenttet = newtet;
10804  //setpoint2tet(insertpt, encode(newtet));
10805  setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
10806 
10807  // Re-use this list to save new interior cavity faces.
10808  cavetetlist->restart();
10809 
10810  // Connect adjacent new tetrahedra together.
10811  for (i = 0; i < cavebdrylist->objects; i++) {
10812  cavetet = (triface *) fastlookup(cavebdrylist, i);
10813  // cavtet is an oldtet, get the newtet at this face.
10814  oldtet = *cavetet;
10815  fsym(oldtet, neightet);
10816  fsym(neightet, newtet);
10817  // Comment: oldtet and newtet must be at the same directed edge.
10818  // Connect the three other faces of this newtet.
10819  for (j = 0; j < 3; j++) {
10820  esym(newtet, neightet); // Go to the face.
10821  if (neightet.tet[neightet.ver & 3] == NULL) {
10822  // Find the adjacent face of this newtet.
10823  spintet = oldtet;
10824  while (1) {
10825  fnextself(spintet);
10826  if (!infected(spintet)) break;
10827  }
10828  fsym(spintet, newneitet);
10829  esymself(newneitet);
10830  bond(neightet, newneitet);
10831  if (ivf->lawson > 1) {
10832  cavetetlist->newindex((void **) &parytet);
10833  *parytet = neightet;
10834  }
10835  }
10836  //setpoint2tet(org(newtet), encode(newtet));
10837  setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
10838  enextself(newtet);
10839  enextself(oldtet);
10840  }
10841  *cavetet = newtet; // Save the new tet.
10842  } // i
10843 
10844  if (checksubfaceflag) {
10845  // Connect subfaces on the boundary of the cavity to the new tets.
10846  for (i = 0; i < cavetetshlist->objects; i++) {
10847  parysh = (face *) fastlookup(cavetetshlist, i);
10848  // Connect it if it is not a missing subface.
10849  if (!sinfected(*parysh)) {
10850  stpivot(*parysh, neightet);
10851  fsym(neightet, spintet);
10852  sesymself(*parysh);
10853  tsbond(spintet, *parysh);
10854  }
10855  }
10856  }
10857 
10858  if (checksubsegflag) {
10859  // Connect segments on the boundary of the cavity to the new tets.
10860  for (i = 0; i < cavetetseglist->objects; i++) {
10861  paryseg = (face *) fastlookup(cavetetseglist, i);
10862  // Connect it if it is not a missing segment.
10863  if (!sinfected(*paryseg)) {
10864  sstpivot1(*paryseg, neightet);
10865  spintet = neightet;
10866  while (1) {
10867  tssbond1(spintet, *paryseg);
10868  fnextself(spintet);
10869  if (spintet.tet == neightet.tet) break;
10870  }
10871  }
10872  }
10873  }
10874 
10875  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10876  ((splitseg != NULL) && (splitseg->sh != NULL))) {
10877  // Split a subface or a segment.
10878  sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
10879  }
10880 
10881  if (checksubfaceflag) {
10882  if (ivf->splitbdflag) {
10883  // Recover new subfaces in C(p).
10884  for (i = 0; i < caveshbdlist->objects; i++) {
10885  // Get an old subface at edge [a, b].
10886  parysh = (face *) fastlookup(caveshbdlist, i);
10887  spivot(*parysh, checksh); // The new subface [a, b, p].
10888  // Do not recover a deleted new face (degenerated).
10889  if (checksh.sh[3] != NULL) {
10890  // Note that the old subface still connects to adjacent old tets
10891  // of C(p), which still connect to the tets outside C(p).
10892  stpivot(*parysh, neightet);
10893  // Find the adjacent tet containing the edge [a,b] outside C(p).
10894  spintet = neightet;
10895  while (1) {
10896  fnextself(spintet);
10897  if (!infected(spintet)) break;
10898  }
10899  // The adjacent tet connects to a new tet in C(p).
10900  fsym(spintet, neightet);
10901  // Find the tet containing the face [a, b, p].
10902  spintet = neightet;
10903  while (1) {
10904  fnextself(spintet);
10905  if (apex(spintet) == insertpt) break;
10906  }
10907  // Adjust the edge direction in spintet and checksh.
10908  if (sorg(checksh) != org(spintet)) {
10909  sesymself(checksh);
10910  }
10911  // Connect the subface to two adjacent tets.
10912  tsbond(spintet, checksh);
10913  fsymself(spintet);
10914  sesymself(checksh);
10915  tsbond(spintet, checksh);
10916  } // if (checksh.sh[3] != NULL)
10917  }
10918  } else {
10919  // The Boundary recovery phase.
10920  // Put all new subfaces into stack for recovery.
10921  for (i = 0; i < caveshbdlist->objects; i++) {
10922  // Get an old subface at edge [a, b].
10923  parysh = (face *) fastlookup(caveshbdlist, i);
10924  spivot(*parysh, checksh); // The new subface [a, b, p].
10925  // Do not recover a deleted new face (degenerated).
10926  if (checksh.sh[3] != NULL) {
10927  subfacstack->newindex((void **) &parysh);
10928  *parysh = checksh;
10929  }
10930  }
10931  // Put all interior subfaces into stack for recovery.
10932  for (i = 0; i < caveencshlist->objects; i++) {
10933  parysh = (face *) fastlookup(caveencshlist, i);
10934  // Some subfaces inside C(p) might be split in sinsertvertex().
10935  // Only queue those faces which are not split.
10936  if (!smarktested(*parysh)) {
10937  checksh = *parysh;
10938  suninfect(checksh);
10939  stdissolve(checksh); // Detach connections to old tets.
10940  subfacstack->newindex((void **) &parysh);
10941  *parysh = checksh;
10942  }
10943  }
10944  }
10945  } // if (checksubfaceflag)
10946 
10947  if (checksubsegflag) {
10948  if (ivf->splitbdflag) {
10949  if (splitseg != NULL) {
10950  // Recover the two new subsegments in C(p).
10951  for (i = 0; i < cavesegshlist->objects; i++) {
10952  paryseg = (face *) fastlookup(cavesegshlist, i);
10953  // Insert this subsegment into C(p).
10954  checkseg = *paryseg;
10955  // Get the adjacent new subface.
10956  checkseg.shver = 0;
10957  spivot(checkseg, checksh);
10958  if (checksh.sh != NULL) {
10959  // Get the adjacent new tetrahedron.
10960  stpivot(checksh, neightet);
10961  } else {
10962  // It's a dangling segment.
10963  point2tetorg(sorg(checkseg), neightet);
10964  finddirection(&neightet, sdest(checkseg));
10965  }
10966  sstbond1(checkseg, neightet);
10967  spintet = neightet;
10968  while (1) {
10969  tssbond1(spintet, checkseg);
10970  fnextself(spintet);
10971  if (spintet.tet == neightet.tet) break;
10972  }
10973  }
10974  } // if (splitseg != NULL)
10975  } else {
10976  // The Boundary Recovery Phase.
10977  // Queue missing segments in C(p) for recovery.
10978  if (splitseg != NULL) {
10979  // Queue two new subsegments in C(p) for recovery.
10980  for (i = 0; i < cavesegshlist->objects; i++) {
10981  paryseg = (face *) fastlookup(cavesegshlist, i);
10982  checkseg = *paryseg;
10983  //sstdissolve1(checkseg); // It has not been connected yet.
10984  s = randomnation(subsegstack->objects + 1);
10985  subsegstack->newindex((void **) &paryseg);
10986  *paryseg = * (face *) fastlookup(subsegstack, s);
10987  paryseg = (face *) fastlookup(subsegstack, s);
10988  *paryseg = checkseg;
10989  }
10990  } // if (splitseg != NULL)
10991  for (i = 0; i < caveencseglist->objects; i++) {
10992  paryseg = (face *) fastlookup(caveencseglist, i);
10993  if (!smarktested(*paryseg)) { // It may be split.
10994  checkseg = *paryseg;
10995  suninfect(checkseg);
10996  sstdissolve1(checkseg); // Detach connections to old tets.
10997  s = randomnation(subsegstack->objects + 1);
10998  subsegstack->newindex((void **) &paryseg);
10999  *paryseg = * (face *) fastlookup(subsegstack, s);
11000  paryseg = (face *) fastlookup(subsegstack, s);
11001  *paryseg = checkseg;
11002  }
11003  }
11004  }
11005  } // if (checksubsegflag)
11006 
11007  if (b->weighted
11008  ) {
11009  // Some vertices may be completed inside the cavity. They must be
11010  // detected and added to recovering list.
11011  // Since every "live" vertex must contain a pointer to a non-dead
11012  // tetrahedron, we can check for each vertex this pointer.
11013  for (i = 0; i < cavetetvertlist->objects; i++) {
11014  pts = (point *) fastlookup(cavetetvertlist, i);
11015  decode(point2tet(*pts), *searchtet);
11016  if (infected(*searchtet)) {
11017  if (b->weighted) {
11018  if (b->verbose > 1) {
11019  printf(" Point #%d is non-regular after the insertion of #%d.\n",
11020  pointmark(*pts), pointmark(insertpt));
11021  }
11022  setpointtype(*pts, NREGULARVERTEX);
11023  nonregularcount++;
11024  }
11025  }
11026  }
11027  }
11028 
11029  if (ivf->chkencflag & 1) {
11030  // Queue all segment outside C(p).
11031  for (i = 0; i < cavetetseglist->objects; i++) {
11032  paryseg = (face *) fastlookup(cavetetseglist, i);
11033  // Skip if it is the split segment.
11034  if (!sinfected(*paryseg)) {
11035  enqueuesubface(badsubsegs, paryseg);
11036  }
11037  }
11038  if (splitseg != NULL) {
11039  // Queue the two new subsegments inside C(p).
11040  for (i = 0; i < cavesegshlist->objects; i++) {
11041  paryseg = (face *) fastlookup(cavesegshlist, i);
11042  enqueuesubface(badsubsegs, paryseg);
11043  }
11044  }
11045  } // if (chkencflag & 1)
11046 
11047  if (ivf->chkencflag & 2) {
11048  // Queue all subfaces outside C(p).
11049  for (i = 0; i < cavetetshlist->objects; i++) {
11050  parysh = (face *) fastlookup(cavetetshlist, i);
11051  // Skip if it is a split subface.
11052  if (!sinfected(*parysh)) {
11053  enqueuesubface(badsubfacs, parysh);
11054  }
11055  }
11056  // Queue all new subfaces inside C(p).
11057  for (i = 0; i < caveshbdlist->objects; i++) {
11058  // Get an old subface at edge [a, b].
11059  parysh = (face *) fastlookup(caveshbdlist, i);
11060  spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
11061  // Do not recover a deleted new face (degenerated).
11062  if (checksh.sh[3] != NULL) {
11063  enqueuesubface(badsubfacs, &checksh);
11064  }
11065  }
11066  } // if (chkencflag & 2)
11067 
11068  if (ivf->chkencflag & 4) {
11069  // Queue all new tetrahedra in C(p).
11070  for (i = 0; i < cavebdrylist->objects; i++) {
11071  cavetet = (triface *) fastlookup(cavebdrylist, i);
11072  enqueuetetrahedron(cavetet);
11073  }
11074  }
11075 
11076  // C(p) is re-meshed successfully.
11077 
11078  // Delete the old tets in C(p).
11079  for (i = 0; i < caveoldtetlist->objects; i++) {
11080  searchtet = (triface *) fastlookup(caveoldtetlist, i);
11081  if (ishulltet(*searchtet)) {
11082  hullsize--;
11083  }
11084  tetrahedrondealloc(searchtet->tet);
11085  }
11086 
11087  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
11088  ((splitseg != NULL) && (splitseg->sh != NULL))) {
11089  // Delete the old subfaces in sC(p).
11090  for (i = 0; i < caveshlist->objects; i++) {
11091  parysh = (face *) fastlookup(caveshlist, i);
11092  if (checksubfaceflag) {//if (bowywat == 2) {
11093  // It is possible that this subface still connects to adjacent
11094  // tets which are not in C(p). If so, clear connections in the
11095  // adjacent tets at this subface.
11096  stpivot(*parysh, neightet);
11097  if (neightet.tet != NULL) {
11098  if (neightet.tet[4] != NULL) {
11099  // Found an adjacent tet. It must be not in C(p).
11100  tsdissolve(neightet);
11101  fsymself(neightet);
11102  tsdissolve(neightet);
11103  }
11104  }
11105  }
11106  shellfacedealloc(subfaces, parysh->sh);
11107  }
11108  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
11109  // Delete the old segment in sC(p).
11110  shellfacedealloc(subsegs, splitseg->sh);
11111  }
11112  }
11113 
11114  if (ivf->lawson) {
11115  for (i = 0; i < cavebdrylist->objects; i++) {
11116  searchtet = (triface *) fastlookup(cavebdrylist, i);
11117  flippush(flipstack, searchtet);
11118  }
11119  if (ivf->lawson > 1) {
11120  for (i = 0; i < cavetetlist->objects; i++) {
11121  searchtet = (triface *) fastlookup(cavetetlist, i);
11122  flippush(flipstack, searchtet);
11123  }
11124  }
11125  }
11126 
11127 
11128  // Clean the working lists.
11129 
11130  caveoldtetlist->restart();
11131  cavebdrylist->restart();
11132  cavetetlist->restart();
11133 
11134  if (checksubsegflag) {
11135  cavetetseglist->restart();
11136  caveencseglist->restart();
11137  }
11138 
11139  if (checksubfaceflag) {
11140  cavetetshlist->restart();
11141  caveencshlist->restart();
11142  }
11143 
11144  if (b->weighted || ivf->smlenflag
11145  ) {
11146  cavetetvertlist->restart();
11147  }
11148 
11149  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
11150  ((splitseg != NULL) && (splitseg->sh != NULL))) {
11151  caveshlist->restart();
11152  caveshbdlist->restart();
11153  cavesegshlist->restart();
11154  }
11155 
11156  return 1; // Point is inserted.
11157 }
11158 
11160 // //
11161 // insertpoint_abort() Abort the insertion of a new vertex. //
11162 // //
11163 // The cavity will be restored. All working lists are cleared. //
11164 // //
11166 
11167 void tetgenmesh::insertpoint_abort(face *splitseg, insertvertexflags *ivf)
11168 {
11169  triface *cavetet;
11170  face *parysh;
11171  int i;
11172 
11173  for (i = 0; i < caveoldtetlist->objects; i++) {
11174  cavetet = (triface *) fastlookup(caveoldtetlist, i);
11175  uninfect(*cavetet);
11176  unmarktest(*cavetet);
11177  }
11178  for (i = 0; i < cavebdrylist->objects; i++) {
11179  cavetet = (triface *) fastlookup(cavebdrylist, i);
11180  unmarktest(*cavetet);
11181  }
11182  cavetetlist->restart();
11183  cavebdrylist->restart();
11184  caveoldtetlist->restart();
11185  cavetetseglist->restart();
11186  cavetetshlist->restart();
11187  if (ivf->splitbdflag) {
11188  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
11189  sunmarktest(*splitseg);
11190  }
11191  for (i = 0; i < caveshlist->objects; i++) {
11192  parysh = (face *) fastlookup(caveshlist, i);
11193  sunmarktest(*parysh);
11194  }
11195  caveshlist->restart();
11196  cavesegshlist->restart();
11197  }
11198 }
11199 
11203 
11207 
11209 // //
11210 // transfernodes() Read the vertices from the input (tetgenio). //
11211 // //
11212 // Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
11213 // All points are indexed (the first point index is 'in->firstnumber'). Each //
11214 // point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
11215 // ...) and the diameter (longest) of the point set are calculated. //
11216 // //
11218 
11219 void tetgenmesh::transfernodes()
11220 {
11221  point pointloop;
11222  REAL x, y, z, w;
11223  int coordindex;
11224  int attribindex;
11225  int mtrindex;
11226  int i, j;
11227 
11228  // Read the points.
11229  coordindex = 0;
11230  attribindex = 0;
11231  mtrindex = 0;
11232  for (i = 0; i < in->numberofpoints; i++) {
11233  makepoint(&pointloop, UNUSEDVERTEX);
11234  // Read the point coordinates.
11235  x = pointloop[0] = in->pointlist[coordindex++];
11236  y = pointloop[1] = in->pointlist[coordindex++];
11237  z = pointloop[2] = in->pointlist[coordindex++];
11238  // Read the point attributes. (Including point weights.)
11239  for (j = 0; j < in->numberofpointattributes; j++) {
11240  pointloop[3 + j] = in->pointattributelist[attribindex++];
11241  }
11242  // Read the point metric tensor.
11243  for (j = 0; j < in->numberofpointmtrs; j++) {
11244  pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
11245  }
11246  if (b->weighted) { // -w option
11247  if (in->numberofpointattributes > 0) {
11248  // The first point attribute is its weight.
11249  //w = in->pointattributelist[in->numberofpointattributes * i];
11250  w = pointloop[3];
11251  } else {
11252  // No given weight available. Default choose the maximum
11253  // absolute value among its coordinates.
11254  w = fabs(x);
11255  if (w < fabs(y)) w = fabs(y);
11256  if (w < fabs(z)) w = fabs(z);
11257  }
11258  if (b->weighted_param == 0) {
11259  pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
11260  } else { // -w1 option
11261  pointloop[3] = w; // Regular tetrahedralization.
11262  }
11263  }
11264  // Determine the smallest and largest x, y and z coordinates.
11265  if (i == 0) {
11266  xmin = xmax = x;
11267  ymin = ymax = y;
11268  zmin = zmax = z;
11269  } else {
11270  xmin = (x < xmin) ? x : xmin;
11271  xmax = (x > xmax) ? x : xmax;
11272  ymin = (y < ymin) ? y : ymin;
11273  ymax = (y > ymax) ? y : ymax;
11274  zmin = (z < zmin) ? z : zmin;
11275  zmax = (z > zmax) ? z : zmax;
11276  }
11277  if (b->psc) {
11278  // Read the geometry parameters.
11279  setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
11280  setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
11281  setpointgeomtag(pointloop, in->pointparamlist[i].tag);
11282  if (in->pointparamlist[i].type == 0) {
11283  setpointtype(pointloop, RIDGEVERTEX);
11284  } else if (in->pointparamlist[i].type == 1) {
11285  setpointtype(pointloop, FREESEGVERTEX);
11286  } else if (in->pointparamlist[i].type == 2) {
11287  setpointtype(pointloop, FREEFACETVERTEX);
11288  } else if (in->pointparamlist[i].type == 3) {
11289  setpointtype(pointloop, FREEVOLVERTEX);
11290  }
11291  }
11292  }
11293 
11294  // 'longest' is the largest possible edge length formed by input vertices.
11295  x = xmax - xmin;
11296  y = ymax - ymin;
11297  z = zmax - zmin;
11298  longest = sqrt(x * x + y * y + z * z);
11299  if (longest == 0.0) {
11300  printf("Error: The point set is trivial.\n");
11301  terminatetetgen(this, 10);
11302  }
11303  // Two identical points are distinguished by 'minedgelength'.
11304  minedgelength = longest * b->epsilon;
11305 }
11306 
11308 // //
11309 // hilbert_init() Initialize the Gray code permutation table. //
11310 // //
11311 // The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray //
11312 // code sequences traveled by the 1st order Hilbert curve in 3 dimensions. //
11313 // The first column is the Gray code of the entry point of the curve, and //
11314 // the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
11315 // the exit point of curve lies. //
11316 // //
11317 // The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
11318 // indices from 0 to 7, modulo by '3'. The code for generating this table is //
11319 // from: http://graphics.stanford.edu/~seander/bithacks.html. //
11320 // //
11322 
11323 void tetgenmesh::hilbert_init(int n)
11324 {
11325  int gc[8], N, mask, travel_bit;
11326  int e, d, f, k, g;
11327  int v, c;
11328  int i;
11329 
11330  N = (n == 2) ? 4 : 8;
11331  mask = (n == 2) ? 3 : 7;
11332 
11333  // Generate the Gray code sequence.
11334  for (i = 0; i < N; i++) {
11335  gc[i] = i ^ (i >> 1);
11336  }
11337 
11338  for (e = 0; e < N; e++) {
11339  for (d = 0; d < n; d++) {
11340  // Calculate the end point (f).
11341  f = e ^ (1 << d); // Toggle the d-th bit of 'e'.
11342  // travel_bit = 2**p, the bit we want to travel.
11343  travel_bit = e ^ f;
11344  for (i = 0; i < N; i++) {
11345  // // Rotate gc[i] left by (p + 1) % n bits.
11346  k = gc[i] * (travel_bit * 2);
11347  g = ((k | (k / N)) & mask);
11348  // Calculate the permuted Gray code by xor with the start point (e).
11349  transgc[e][d][i] = (g ^ e);
11350  }
11351  } // d
11352  } // e
11353 
11354  // Count the consecutive '1' bits (trailing) on the right.
11355  tsb1mod3[0] = 0;
11356  for (i = 1; i < N; i++) {
11357  v = ~i; // Count the 0s.
11358  v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
11359  for (c = 0; v; c++) {
11360  v >>= 1;
11361  }
11362  tsb1mod3[i] = c % n;
11363  }
11364 }
11365 
11367 // //
11368 // hilbert_sort3() Sort points using the 3d Hilbert curve. //
11369 // //
11371 
11372 int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
11373  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
11374  REAL bzmin, REAL bzmax)
11375 {
11376  point swapvert;
11377  int axis, d;
11378  REAL split;
11379  int i, j;
11380 
11381 
11382  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
11383  // correspoding to x-, or y- or z-axis.
11384  axis = (gc0 ^ gc1) >> 1;
11385 
11386  // Calulate the split position along the axis.
11387  if (axis == 0) {
11388  split = 0.5 * (bxmin + bxmax);
11389  } else if (axis == 1) {
11390  split = 0.5 * (bymin + bymax);
11391  } else { // == 2
11392  split = 0.5 * (bzmin + bzmax);
11393  }
11394 
11395  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
11396  // of the axis is to the positive of the axis, otherwise, it is -1.
11397  d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
11398 
11399 
11400  // Partition the vertices into left- and right-arrays such that left points
11401  // have Hilbert indices lower than the right points.
11402  i = 0;
11403  j = arraysize - 1;
11404 
11405  // Partition the vertices into left- and right-arrays.
11406  if (d > 0) {
11407  do {
11408  for (; i < arraysize; i++) {
11409  if (vertexarray[i][axis] >= split) break;
11410  }
11411  for (; j >= 0; j--) {
11412  if (vertexarray[j][axis] < split) break;
11413  }
11414  // Is the partition finished?
11415  if (i == (j + 1)) break;
11416  // Swap i-th and j-th vertices.
11417  swapvert = vertexarray[i];
11418  vertexarray[i] = vertexarray[j];
11419  vertexarray[j] = swapvert;
11420  // Continue patitioning the array;
11421  } while (true);
11422  } else {
11423  do {
11424  for (; i < arraysize; i++) {
11425  if (vertexarray[i][axis] <= split) break;
11426  }
11427  for (; j >= 0; j--) {
11428  if (vertexarray[j][axis] > split) break;
11429  }
11430  // Is the partition finished?
11431  if (i == (j + 1)) break;
11432  // Swap i-th and j-th vertices.
11433  swapvert = vertexarray[i];
11434  vertexarray[i] = vertexarray[j];
11435  vertexarray[j] = swapvert;
11436  // Continue patitioning the array;
11437  } while (true);
11438  }
11439 
11440  return i;
11441 }
11442 
11443 void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
11444  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
11445  REAL bzmin, REAL bzmax, int depth)
11446 {
11447  REAL x1, x2, y1, y2, z1, z2;
11448  int p[9], w, e_w, d_w, k, ei, di;
11449  int n = 3, mask = 7;
11450 
11451  p[0] = 0;
11452  p[8] = arraysize;
11453 
11454  // Sort the points according to the 1st order Hilbert curve in 3d.
11455  p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4],
11456  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
11457  p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2],
11458  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
11459  p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1],
11460  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
11461  p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2],
11462  transgc[e][d][2], transgc[e][d][3],
11463  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
11464  p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4],
11465  transgc[e][d][5], transgc[e][d][6],
11466  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
11467  p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4],
11468  transgc[e][d][4], transgc[e][d][5],
11469  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
11470  p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6],
11471  transgc[e][d][6], transgc[e][d][7],
11472  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
11473 
11474  if (b->hilbert_order > 0) {
11475  // A maximum order is prescribed.
11476  if ((depth + 1) == b->hilbert_order) {
11477  // The maximum prescribed order is reached.
11478  return;
11479  }
11480  }
11481 
11482  // Recursively sort the points in sub-boxes.
11483  for (w = 0; w < 8; w++) {
11484  // w is the local Hilbert index (NOT Gray code).
11485  // Sort into the sub-box either there are more than 2 points in it, or
11486  // the prescribed order of the curve is not reached yet.
11487  //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
11488  if ((p[w+1] - p[w]) > b->hilbert_limit) {
11489  // Calculcate the start point (ei) of the curve in this sub-box.
11490  // update e = e ^ (e(w) left_rotate (d+1)).
11491  if (w == 0) {
11492  e_w = 0;
11493  } else {
11494  // calculate e(w) = gc(2 * floor((w - 1) / 2)).
11495  k = 2 * ((w - 1) / 2);
11496  e_w = k ^ (k >> 1); // = gc(k).
11497  }
11498  k = e_w;
11499  e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
11500  ei = e ^ e_w;
11501  // Calulcate the direction (di) of the curve in this sub-box.
11502  // update d = (d + d(w) + 1) % n
11503  if (w == 0) {
11504  d_w = 0;
11505  } else {
11506  d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
11507  }
11508  di = (d + d_w + 1) % n;
11509  // Calculate the bounding box of the sub-box.
11510  if (transgc[e][d][w] & 1) { // x-axis
11511  x1 = 0.5 * (bxmin + bxmax);
11512  x2 = bxmax;
11513  } else {
11514  x1 = bxmin;
11515  x2 = 0.5 * (bxmin + bxmax);
11516  }
11517  if (transgc[e][d][w] & 2) { // y-axis
11518  y1 = 0.5 * (bymin + bymax);
11519  y2 = bymax;
11520  } else {
11521  y1 = bymin;
11522  y2 = 0.5 * (bymin + bymax);
11523  }
11524  if (transgc[e][d][w] & 4) { // z-axis
11525  z1 = 0.5 * (bzmin + bzmax);
11526  z2 = bzmax;
11527  } else {
11528  z1 = bzmin;
11529  z2 = 0.5 * (bzmin + bzmax);
11530  }
11531  hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di,
11532  x1, x2, y1, y2, z1, z2, depth+1);
11533  } // if (p[w+1] - p[w] > 1)
11534  } // w
11535 }
11536 
11538 // //
11539 // brio_multiscale_sort() Sort the points using BRIO and Hilbert curve. //
11540 // //
11542 
11543 void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize,
11544  int threshold, REAL ratio, int *depth)
11545 {
11546  int middle;
11547 
11548  middle = 0;
11549  if (arraysize >= threshold) {
11550  (*depth)++;
11551  middle = arraysize * ratio;
11552  brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
11553  }
11554  // Sort the right-array (rnd-th round) using the Hilbert curve.
11555  hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
11556  xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
11557 }
11558 
11560 // //
11561 // randomnation() Generate a random number between 0 and 'choices' - 1. //
11562 // //
11564 
11565 unsigned long tetgenmesh::randomnation(unsigned int choices)
11566 {
11567  unsigned long newrandom;
11568 
11569  if (choices >= 714025l) {
11570  newrandom = (randomseed * 1366l + 150889l) % 714025l;
11571  randomseed = (newrandom * 1366l + 150889l) % 714025l;
11572  newrandom = newrandom * (choices / 714025l) + randomseed;
11573  if (newrandom >= choices) {
11574  return newrandom - choices;
11575  } else {
11576  return newrandom;
11577  }
11578  } else {
11579  randomseed = (randomseed * 1366l + 150889l) % 714025l;
11580  return randomseed % choices;
11581  }
11582 }
11583 
11585 // //
11586 // randomsample() Randomly sample the tetrahedra for point loation. //
11587 // //
11588 // Searching begins from one of handles: the input 'searchtet', a recently //
11589 // encountered tetrahedron 'recenttet', or from one chosen from a random //
11590 // sample. The choice is made by determining which one's origin is closest //
11591 // to the point we are searching for. //
11592 // //
11594 
11595 void tetgenmesh::randomsample(point searchpt,triface *searchtet)
11596 {
11597  tetrahedron *firsttet, *tetptr;
11598  point torg;
11599  void **sampleblock;
11600  uintptr_t alignptr;
11601  long sampleblocks, samplesperblock, samplenum;
11602  long tetblocks, i, j;
11603  REAL searchdist, dist;
11604 
11605  if (b->verbose > 2) {
11606  printf(" Random sampling tetrahedra for searching point %d.\n",
11607  pointmark(searchpt));
11608  }
11609 
11610  if (!nonconvex) {
11611  if (searchtet->tet == NULL) {
11612  // A null tet. Choose the recenttet as the starting tet.
11613  *searchtet = recenttet;
11614  }
11615 
11616  // 'searchtet' should be a valid tetrahedron. Choose the base face
11617  // whose vertices must not be 'dummypoint'.
11618  searchtet->ver = 3;
11619  // Record the distance from its origin to the searching point.
11620  torg = org(*searchtet);
11621  searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11622  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11623  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11624 
11625  // If a recently encountered tetrahedron has been recorded and has not
11626  // been deallocated, test it as a good starting point.
11627  if (recenttet.tet != searchtet->tet) {
11628  recenttet.ver = 3;
11629  torg = org(recenttet);
11630  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11631  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11632  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11633  if (dist < searchdist) {
11634  *searchtet = recenttet;
11635  searchdist = dist;
11636  }
11637  }
11638  } else {
11639  // The mesh is non-convex. Do not use 'recenttet'.
11640  searchdist = longest;
11641  }
11642 
11643  // Select "good" candidate using k random samples, taking the closest one.
11644  // The number of random samples taken is proportional to the fourth root
11645  // of the number of tetrahedra in the mesh.
11646  while (samples * samples * samples * samples < tetrahedrons->items) {
11647  samples++;
11648  }
11649  // Find how much blocks in current tet pool.
11650  tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1)
11651  / b->tetrahedraperblock;
11652  // Find the average samples per block. Each block at least have 1 sample.
11653  samplesperblock = 1 + (samples / tetblocks);
11654  sampleblocks = samples / samplesperblock;
11655  sampleblock = tetrahedrons->firstblock;
11656  for (i = 0; i < sampleblocks; i++) {
11657  alignptr = (uintptr_t) (sampleblock + 1);
11658  firsttet = (tetrahedron *)
11659  (alignptr + (uintptr_t) tetrahedrons->alignbytes
11660  - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
11661  for (j = 0; j < samplesperblock; j++) {
11662  if (i == tetblocks - 1) {
11663  // This is the last block.
11664  samplenum = randomnation((int)
11665  (tetrahedrons->maxitems - (i * b->tetrahedraperblock)));
11666  } else {
11667  samplenum = randomnation(b->tetrahedraperblock);
11668  }
11669  tetptr = (tetrahedron *)
11670  (firsttet + (samplenum * tetrahedrons->itemwords));
11671  torg = (point) tetptr[4];
11672  if (torg != (point) NULL) {
11673  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11674  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11675  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11676  if (dist < searchdist) {
11677  searchtet->tet = tetptr;
11678  searchtet->ver = 11; // torg = org(t);
11679  searchdist = dist;
11680  }
11681  } else {
11682  // A dead tet. Re-sample it.
11683  if (i != tetblocks - 1) j--;
11684  }
11685  }
11686  sampleblock = (void **) *sampleblock;
11687  }
11688 }
11689 
11691 // //
11692 // locate() Find a tetrahedron containing a given point. //
11693 // //
11694 // Begins its search from 'searchtet', assume there is a line segment L from //
11695 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
11696 // towards 'searchpt' by traversing all faces intersected by L. //
11697 // //
11698 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
11699 // returned value indicates one of the following cases: //
11700 // - ONVERTEX, the search point lies on the origin of 'searchtet'. //
11701 // - ONEDGE, the search point lies on an edge of 'searchtet'. //
11702 // - ONFACE, the search point lies on a face of 'searchtet'. //
11703 // - INTET, the search point lies in the interior of 'searchtet'. //
11704 // - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a //
11705 // hull face which is visible by the search point. //
11706 // //
11707 // WARNING: This routine is designed for convex triangulations, and will not //
11708 // generally work after the holes and concavities have been carved. //
11709 // //
11711 
11712 enum tetgenmesh::locateresult
11713  tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag)
11714 {
11715  point torg, tdest, tapex, toppo;
11716  enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
11717  REAL ori, oriorg, oridest, oriapex;
11718  enum locateresult loc = OUTSIDE;
11719  int t1ver;
11720  int s;
11721 
11722  torg = tdest = tapex = toppo = NULL;
11723 
11724  if (searchtet->tet == NULL) {
11725  // A null tet. Choose the recenttet as the starting tet.
11726  searchtet->tet = recenttet.tet;
11727  }
11728 
11729  // Check if we are in the outside of the convex hull.
11730  if (ishulltet(*searchtet)) {
11731  // Get its adjacent tet (inside the hull).
11732  searchtet->ver = 3;
11733  fsymself(*searchtet);
11734  }
11735 
11736  // Let searchtet be the face such that 'searchpt' lies above to it.
11737  for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
11738  torg = org(*searchtet);
11739  tdest = dest(*searchtet);
11740  tapex = apex(*searchtet);
11741  ori = orient3d(torg, tdest, tapex, searchpt);
11742  if (ori < 0.0) break;
11743  }
11744  if (searchtet->ver == 4) {
11745  terminatetetgen(this, 2);
11746  }
11747 
11748  // Walk through tetrahedra to locate the point.
11749  while (true) {
11750 
11751  toppo = oppo(*searchtet);
11752 
11753  // Check if the vertex is we seek.
11754  if (toppo == searchpt) {
11755  // Adjust the origin of searchtet to be searchpt.
11756  esymself(*searchtet);
11757  eprevself(*searchtet);
11758  loc = ONVERTEX; // return ONVERTEX;
11759  break;
11760  }
11761 
11762  // We enter from one of serarchtet's faces, which face do we exit?
11763  oriorg = orient3d(tdest, tapex, toppo, searchpt);
11764  oridest = orient3d(tapex, torg, toppo, searchpt);
11765  oriapex = orient3d(torg, tdest, toppo, searchpt);
11766 
11767  // Now decide which face to move. It is possible there are more than one
11768  // faces are viable moves. If so, randomly choose one.
11769  if (oriorg < 0) {
11770  if (oridest < 0) {
11771  if (oriapex < 0) {
11772  // All three faces are possible.
11773  s = randomnation(3); // 's' is in {0,1,2}.
11774  if (s == 0) {
11775  nextmove = ORGMOVE;
11776  } else if (s == 1) {
11777  nextmove = DESTMOVE;
11778  } else {
11779  nextmove = APEXMOVE;
11780  }
11781  } else {
11782  // Two faces, opposite to origin and destination, are viable.
11783  //s = randomnation(2); // 's' is in {0,1}.
11784  if (randomnation(2)) {
11785  nextmove = ORGMOVE;
11786  } else {
11787  nextmove = DESTMOVE;
11788  }
11789  }
11790  } else {
11791  if (oriapex < 0) {
11792  // Two faces, opposite to origin and apex, are viable.
11793  //s = randomnation(2); // 's' is in {0,1}.
11794  if (randomnation(2)) {
11795  nextmove = ORGMOVE;
11796  } else {
11797  nextmove = APEXMOVE;
11798  }
11799  } else {
11800  // Only the face opposite to origin is viable.
11801  nextmove = ORGMOVE;
11802  }
11803  }
11804  } else {
11805  if (oridest < 0) {
11806  if (oriapex < 0) {
11807  // Two faces, opposite to destination and apex, are viable.
11808  //s = randomnation(2); // 's' is in {0,1}.
11809  if (randomnation(2)) {
11810  nextmove = DESTMOVE;
11811  } else {
11812  nextmove = APEXMOVE;
11813  }
11814  } else {
11815  // Only the face opposite to destination is viable.
11816  nextmove = DESTMOVE;
11817  }
11818  } else {
11819  if (oriapex < 0) {
11820  // Only the face opposite to apex is viable.
11821  nextmove = APEXMOVE;
11822  } else {
11823  // The point we seek must be on the boundary of or inside this
11824  // tetrahedron. Check for boundary cases.
11825  if (oriorg == 0) {
11826  // Go to the face opposite to origin.
11827  enextesymself(*searchtet);
11828  if (oridest == 0) {
11829  eprevself(*searchtet); // edge oppo->apex
11830  if (oriapex == 0) {
11831  // oppo is duplicated with p.
11832  loc = ONVERTEX; // return ONVERTEX;
11833  break;
11834  }
11835  loc = ONEDGE; // return ONEDGE;
11836  break;
11837  }
11838  if (oriapex == 0) {
11839  enextself(*searchtet); // edge dest->oppo
11840  loc = ONEDGE; // return ONEDGE;
11841  break;
11842  }
11843  loc = ONFACE; // return ONFACE;
11844  break;
11845  }
11846  if (oridest == 0) {
11847  // Go to the face opposite to destination.
11848  eprevesymself(*searchtet);
11849  if (oriapex == 0) {
11850  eprevself(*searchtet); // edge oppo->org
11851  loc = ONEDGE; // return ONEDGE;
11852  break;
11853  }
11854  loc = ONFACE; // return ONFACE;
11855  break;
11856  }
11857  if (oriapex == 0) {
11858  // Go to the face opposite to apex
11859  esymself(*searchtet);
11860  loc = ONFACE; // return ONFACE;
11861  break;
11862  }
11863  loc = INTETRAHEDRON; // return INTETRAHEDRON;
11864  break;
11865  }
11866  }
11867  }
11868 
11869  // Move to the selected face.
11870  if (nextmove == ORGMOVE) {
11871  enextesymself(*searchtet);
11872  } else if (nextmove == DESTMOVE) {
11873  eprevesymself(*searchtet);
11874  } else {
11875  esymself(*searchtet);
11876  }
11877  if (chkencflag) {
11878  // Check if we are walking across a subface.
11879  if (issubface(*searchtet)) {
11880  loc = ENCSUBFACE;
11881  break;
11882  }
11883  }
11884  // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
11885  fsymself(*searchtet);
11886  if (oppo(*searchtet) == dummypoint) {
11887  loc = OUTSIDE; // return OUTSIDE;
11888  break;
11889  }
11890 
11891  // Retreat the three vertices of the base face.
11892  torg = org(*searchtet);
11893  tdest = dest(*searchtet);
11894  tapex = apex(*searchtet);
11895 
11896  } // while (true)
11897 
11898  return loc;
11899 }
11900 
11902 // //
11903 // flippush() Push a face (possibly will be flipped) into flipstack. //
11904 // //
11905 // The face is marked. The flag is used to check the validity of the face on //
11906 // its popup. Some other flips may change it already. //
11907 // //
11909 
11910 void tetgenmesh::flippush(badface*& fstack, triface* flipface)
11911 {
11912  if (!facemarked(*flipface)) {
11913  badface *newflipface = (badface *) flippool->alloc();
11914  newflipface->tt = *flipface;
11915  markface(newflipface->tt);
11916  // Push this face into stack.
11917  newflipface->nextitem = fstack;
11918  fstack = newflipface;
11919  }
11920 }
11921 
11923 // //
11924 // incrementalflip() Incrementally flipping to construct DT. //
11925 // //
11926 // Faces need to be checked for flipping are already queued in 'flipstack'. //
11927 // Return the total number of performed flips. //
11928 // //
11929 // Comment: This routine should be only used in the incremental Delaunay //
11930 // construction. In other cases, lawsonflip3d() should be used. //
11931 // //
11932 // If the new point lies outside of the convex hull ('hullflag' is set). The //
11933 // incremental flip algorithm still works as usual. However, we must ensure //
11934 // that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
11935 // edge or face. Otherwise, the underlying space of the triangulation becomes//
11936 // non-manifold and it is not possible to flip further. //
11937 // Thanks to Joerg Rambau and Frank Lutz for helping in this issue. //
11938 // //
11940 
11941 int tetgenmesh::incrementalflip(point newpt, int hullflag, flipconstraints *fc)
11942 {
11943  badface *popface;
11944  triface fliptets[5], *parytet;
11945  point *pts, *parypt, pe;
11946  REAL sign, ori;
11947  int flipcount = 0;
11948  int t1ver;
11949  int i;
11950 
11951  if (b->verbose > 2) {
11952  printf(" Lawson flip (%ld faces).\n", flippool->items);
11953  }
11954 
11955  if (hullflag) {
11956  // 'newpt' lies in the outside of the convex hull.
11957  // Mark all hull vertices which are connecting to it.
11958  popface = flipstack;
11959  while (popface != NULL) {
11960  pts = (point *) popface->tt.tet;
11961  for (i = 4; i < 8; i++) {
11962  if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
11963  if (!pinfected(pts[i])) {
11964  pinfect(pts[i]);
11965  cavetetvertlist->newindex((void **) &parypt);
11966  *parypt = pts[i];
11967  }
11968  }
11969  }
11970  popface = popface->nextitem;
11971  }
11972  }
11973 
11974  // Loop until the queue is empty.
11975  while (flipstack != NULL) {
11976 
11977  // Pop a face from the stack.
11978  popface = flipstack;
11979  fliptets[0] = popface->tt;
11980  flipstack = flipstack->nextitem; // The next top item in stack.
11981  flippool->dealloc((void *) popface);
11982 
11983  // Skip it if it is a dead tet (destroyed by previous flips).
11984  if (isdeadtet(fliptets[0])) continue;
11985  // Skip it if it is not the same tet as we saved.
11986  if (!facemarked(fliptets[0])) continue;
11987 
11988  unmarkface(fliptets[0]);
11989 
11990  if ((point) fliptets[0].tet[7] == dummypoint) {
11991  // It must be a hull edge.
11992  fliptets[0].ver = epivot[fliptets[0].ver];
11993  // A hull edge. The current convex hull may be enlarged.
11994  fsym(fliptets[0], fliptets[1]);
11995  pts = (point *) fliptets[1].tet;
11996  ori = orient3d(pts[4], pts[5], pts[6], newpt);
11997  if (ori < 0) {
11998  // Visible. The convex hull will be enlarged.
11999  // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
12000  // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
12001  enext(fliptets[1], fliptets[2]);
12002  eprev(fliptets[1], fliptets[3]);
12003  fnextself(fliptets[2]); // [a,c,e,*]
12004  fnextself(fliptets[3]); // [c,b,e,*]
12005  if (oppo(fliptets[2]) == newpt) {
12006  if (oppo(fliptets[3]) == newpt) {
12007  // Both tets exist! A 4-to-1 flip is found.
12008  terminatetetgen(this, 2); // Report a bug.
12009  } else {
12010  esym(fliptets[2], fliptets[0]);
12011  fnext(fliptets[0], fliptets[1]);
12012  fnext(fliptets[1], fliptets[2]);
12013  // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
12014  // This corresponds to my standard labels, where edge [e,d] is
12015  // repalced by face [a,b,c], and a is the new vertex.
12016  // [0] [c,a,d,e] (d = newpt)
12017  // [1] [c,a,e,b] (c = dummypoint)
12018  // [2] [c,a,b,d]
12019  flip32(fliptets, 1, fc);
12020  }
12021  } else {
12022  if (oppo(fliptets[3]) == newpt) {
12023  fnext(fliptets[3], fliptets[0]);
12024  fnext(fliptets[0], fliptets[1]);
12025  fnext(fliptets[1], fliptets[2]);
12026  // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
12027  // [0] [c,b,d,a] (d = newpt)
12028  // [1] [c,b,a,e] (c = dummypoint)
12029  // [2] [c,b,e,d]
12030  flip32(fliptets, 1, fc);
12031  } else {
12032  if (hullflag) {
12033  // Reject this flip if pe is already marked.
12034  pe = oppo(fliptets[1]);
12035  if (!pinfected(pe)) {
12036  pinfect(pe);
12037  cavetetvertlist->newindex((void **) &parypt);
12038  *parypt = pe;
12039  // Perform a 2-to-3 flip.
12040  flip23(fliptets, 1, fc);
12041  } else {
12042  // Reject this flip.
12043  flipcount--;
12044  }
12045  } else {
12046  // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
12047  // [0] [a,b,c,d], d = newpt.
12048  // [1] [b,a,c,e], c = dummypoint.
12049  flip23(fliptets, 1, fc);
12050  }
12051  }
12052  }
12053  flipcount++;
12054  }
12055  continue;
12056  } // if (dummypoint)
12057 
12058  fsym(fliptets[0], fliptets[1]);
12059  if ((point) fliptets[1].tet[7] == dummypoint) {
12060  // A hull face is locally Delaunay.
12061  continue;
12062  }
12063  // Check if the adjacent tet has already been tested.
12064  if (marktested(fliptets[1])) {
12065  // It has been tested and it is Delaunay.
12066  continue;
12067  }
12068 
12069  // Test whether the face is locally Delaunay or not.
12070  pts = (point *) fliptets[1].tet;
12071  if (b->weighted) {
12072  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
12073  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
12074  newpt[3]);
12075  } else {
12076  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
12077  }
12078 
12079 
12080  if (sign < 0) {
12081  point pd = newpt;
12082  point pe = oppo(fliptets[1]);
12083  // Check the convexity of its three edges. Stop checking either a
12084  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
12085  // encountered, and 'fliptet' represents that edge.
12086  for (i = 0; i < 3; i++) {
12087  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
12088  if (ori <= 0) break;
12089  enextself(fliptets[0]);
12090  }
12091  if (ori > 0) {
12092  // A 2-to-3 flip is found.
12093  // [0] [a,b,c,d],
12094  // [1] [b,a,c,e]. no dummypoint.
12095  flip23(fliptets, 0, fc);
12096  flipcount++;
12097  } else { // ori <= 0
12098  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
12099  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
12100  // Check if there are three or four tets sharing at this edge.
12101  esymself(fliptets[0]); // [b,a,d,c]
12102  for (i = 0; i < 3; i++) {
12103  fnext(fliptets[i], fliptets[i+1]);
12104  }
12105  if (fliptets[3].tet == fliptets[0].tet) {
12106  // A 3-to-2 flip is found. (No hull tet.)
12107  flip32(fliptets, 0, fc);
12108  flipcount++;
12109  } else {
12110  // There are more than 3 tets at this edge.
12111  fnext(fliptets[3], fliptets[4]);
12112  if (fliptets[4].tet == fliptets[0].tet) {
12113  if (ori == 0) {
12114  // A 4-to-4 flip is found. (Two hull tets may be involved.)
12115  // Current tets in 'fliptets':
12116  // [0] [b,a,d,c] (d may be newpt)
12117  // [1] [b,a,c,e]
12118  // [2] [b,a,e,f] (f may be dummypoint)
12119  // [3] [b,a,f,d]
12120  esymself(fliptets[0]); // [a,b,c,d]
12121  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
12122  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
12123  // It will be removed by the followed 3-to-2 flip.
12124  flip23(fliptets, 0, fc); // No hull tet.
12125  fnext(fliptets[3], fliptets[1]);
12126  fnext(fliptets[1], fliptets[2]);
12127  // Current tets in 'fliptets':
12128  // [0] [...]
12129  // [1] [b,a,d,e] (degenerated, d may be new point).
12130  // [2] [b,a,e,f] (f may be dummypoint)
12131  // [3] [b,a,f,d]
12132  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
12133  // Hull tets may be involved (f may be dummypoint).
12134  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
12135  flipcount++;
12136  }
12137  }
12138  }
12139  } // ori
12140  } else {
12141  // The adjacent tet is Delaunay. Mark it to avoid testing it again.
12142  marktest(fliptets[1]);
12143  // Save it for unmarking it later.
12144  cavebdrylist->newindex((void **) &parytet);
12145  *parytet = fliptets[1];
12146  }
12147 
12148  } // while (flipstack)
12149 
12150  // Unmark saved tetrahedra.
12151  for (i = 0; i < cavebdrylist->objects; i++) {
12152  parytet = (triface *) fastlookup(cavebdrylist, i);
12153  unmarktest(*parytet);
12154  }
12155  cavebdrylist->restart();
12156 
12157  if (hullflag) {
12158  // Unmark infected vertices.
12159  for (i = 0; i < cavetetvertlist->objects; i++) {
12160  parypt = (point *) fastlookup(cavetetvertlist, i);
12161  puninfect(*parypt);
12162  }
12163  cavetetvertlist->restart();
12164  }
12165 
12166 
12167  return flipcount;
12168 }
12169 
12171 // //
12172 // initialdelaunay() Create an initial Delaunay tetrahedralization. //
12173 // //
12174 // The tetrahedralization contains only one tetrahedron abcd, and four hull //
12175 // tetrahedra. The points pa, pb, pc, and pd must be linearly independent. //
12176 // //
12178 
12179 void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
12180 {
12181  triface firsttet, tetopa, tetopb, tetopc, tetopd;
12182  triface worktet, worktet1;
12183 
12184  if (b->verbose > 2) {
12185  printf(" Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
12186  pointmark(pb), pointmark(pc), pointmark(pd));
12187  }
12188 
12189  // Create the first tetrahedron.
12190  maketetrahedron(&firsttet);
12191  setvertices(firsttet, pa, pb, pc, pd);
12192  // Create four hull tetrahedra.
12193  maketetrahedron(&tetopa);
12194  setvertices(tetopa, pb, pc, pd, dummypoint);
12195  maketetrahedron(&tetopb);
12196  setvertices(tetopb, pc, pa, pd, dummypoint);
12197  maketetrahedron(&tetopc);
12198  setvertices(tetopc, pa, pb, pd, dummypoint);
12199  maketetrahedron(&tetopd);
12200  setvertices(tetopd, pb, pa, pc, dummypoint);
12201  hullsize += 4;
12202 
12203  // Connect hull tetrahedra to firsttet (at four faces of firsttet).
12204  bond(firsttet, tetopd);
12205  esym(firsttet, worktet);
12206  bond(worktet, tetopc); // ab
12207  enextesym(firsttet, worktet);
12208  bond(worktet, tetopa); // bc
12209  eprevesym(firsttet, worktet);
12210  bond(worktet, tetopb); // ca
12211 
12212  // Connect hull tetrahedra together (at six edges of firsttet).
12213  esym(tetopc, worktet);
12214  esym(tetopd, worktet1);
12215  bond(worktet, worktet1); // ab
12216  esym(tetopa, worktet);
12217  eprevesym(tetopd, worktet1);
12218  bond(worktet, worktet1); // bc
12219  esym(tetopb, worktet);
12220  enextesym(tetopd, worktet1);
12221  bond(worktet, worktet1); // ca
12222  eprevesym(tetopc, worktet);
12223  enextesym(tetopb, worktet1);
12224  bond(worktet, worktet1); // da
12225  eprevesym(tetopa, worktet);
12226  enextesym(tetopc, worktet1);
12227  bond(worktet, worktet1); // db
12228  eprevesym(tetopb, worktet);
12229  enextesym(tetopa, worktet1);
12230  bond(worktet, worktet1); // dc
12231 
12232  // Set the vertex type.
12233  if (pointtype(pa) == UNUSEDVERTEX) {
12234  setpointtype(pa, VOLVERTEX);
12235  }
12236  if (pointtype(pb) == UNUSEDVERTEX) {
12237  setpointtype(pb, VOLVERTEX);
12238  }
12239  if (pointtype(pc) == UNUSEDVERTEX) {
12240  setpointtype(pc, VOLVERTEX);
12241  }
12242  if (pointtype(pd) == UNUSEDVERTEX) {
12243  setpointtype(pd, VOLVERTEX);
12244  }
12245 
12246  setpoint2tet(pa, encode(firsttet));
12247  setpoint2tet(pb, encode(firsttet));
12248  setpoint2tet(pc, encode(firsttet));
12249  setpoint2tet(pd, encode(firsttet));
12250 
12251  // Remember the first tetrahedron.
12252  recenttet = firsttet;
12253 }
12254 
12256 // //
12257 // incrementaldelaunay() Create a Delaunay tetrahedralization by //
12258 // the incremental approach. //
12259 // //
12261 
12262 
12263 void tetgenmesh::incrementaldelaunay(clock_t& tv)
12264 {
12265  triface searchtet;
12266  point *permutarray, swapvertex;
12267  REAL v1[3], v2[3], n[3];
12268  REAL bboxsize, bboxsize2, bboxsize3, ori;
12269  int randindex;
12270  int ngroup = 0;
12271  int i, j;
12272 
12273  if (!b->quiet) {
12274  printf("Delaunizing vertices...\n");
12275  }
12276 
12277  // Form a random permuation (uniformly at random) of the set of vertices.
12278  permutarray = new point[in->numberofpoints];
12279  points->traversalinit();
12280 
12281  if (b->no_sort) {
12282  if (b->verbose) {
12283  printf(" Using the input order.\n");
12284  }
12285  for (i = 0; i < in->numberofpoints; i++) {
12286  permutarray[i] = (point) points->traverse();
12287  }
12288  } else {
12289  if (b->verbose) {
12290  printf(" Permuting vertices.\n");
12291  }
12292  srand(in->numberofpoints);
12293  for (i = 0; i < in->numberofpoints; i++) {
12294  randindex = rand() % (i + 1); // randomnation(i + 1);
12295  permutarray[i] = permutarray[randindex];
12296  permutarray[randindex] = (point) points->traverse();
12297  }
12298  if (b->brio_hilbert) { // -b option
12299  if (b->verbose) {
12300  printf(" Sorting vertices.\n");
12301  }
12302  hilbert_init(in->mesh_dim);
12303  brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold,
12304  b->brio_ratio, &ngroup);
12305  }
12306  }
12307 
12308  tv = clock(); // Remember the time for sorting points.
12309 
12310  // Calculate the diagonal size of its bounding box.
12311  bboxsize = sqrt(norm2(xmax - xmin, ymax - ymin, zmax - zmin));
12312  bboxsize2 = bboxsize * bboxsize;
12313  bboxsize3 = bboxsize2 * bboxsize;
12314 
12315  // Make sure the second vertex is not identical with the first one.
12316  i = 1;
12317  while ((distance(permutarray[0],permutarray[i])/bboxsize)<b->epsilon) {
12318  i++;
12319  if (i == in->numberofpoints - 1) {
12320  printf("Exception: All vertices are (nearly) identical (Tol = %g).\n",
12321  b->epsilon);
12322  terminatetetgen(this, 10);
12323  }
12324  }
12325  if (i > 1) {
12326  // Swap to move the non-identical vertex from index i to index 1.
12327  swapvertex = permutarray[i];
12328  permutarray[i] = permutarray[1];
12329  permutarray[1] = swapvertex;
12330  }
12331 
12332  // Make sure the third vertex is not collinear with the first two.
12333  // Acknowledgement: Thanks Jan Pomplun for his correction by using
12334  // epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
12335  i = 2;
12336  for (j = 0; j < 3; j++) {
12337  v1[j] = permutarray[1][j] - permutarray[0][j];
12338  v2[j] = permutarray[i][j] - permutarray[0][j];
12339  }
12340  cross(v1, v2, n);
12341  while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) < b->epsilon) {
12342  i++;
12343  if (i == in->numberofpoints - 1) {
12344  printf("Exception: All vertices are (nearly) collinear (Tol = %g).\n",
12345  b->epsilon);
12346  terminatetetgen(this, 10);
12347  }
12348  for (j = 0; j < 3; j++) {
12349  v2[j] = permutarray[i][j] - permutarray[0][j];
12350  }
12351  cross(v1, v2, n);
12352  }
12353  if (i > 2) {
12354  // Swap to move the non-identical vertex from index i to index 1.
12355  swapvertex = permutarray[i];
12356  permutarray[i] = permutarray[2];
12357  permutarray[2] = swapvertex;
12358  }
12359 
12360  // Make sure the fourth vertex is not coplanar with the first three.
12361  i = 3;
12362  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
12363  permutarray[i]);
12364  while ((fabs(ori) / bboxsize3) < b->epsilon) {
12365  i++;
12366  if (i == in->numberofpoints) {
12367  printf("Exception: All vertices are coplanar (Tol = %g).\n",
12368  b->epsilon);
12369  terminatetetgen(this, 10);
12370  }
12371  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
12372  permutarray[i]);
12373  }
12374  if (i > 3) {
12375  // Swap to move the non-identical vertex from index i to index 1.
12376  swapvertex = permutarray[i];
12377  permutarray[i] = permutarray[3];
12378  permutarray[3] = swapvertex;
12379  }
12380 
12381  // Orient the first four vertices in permutarray so that they follow the
12382  // right-hand rule.
12383  if (ori > 0.0) {
12384  // Swap the first two vertices.
12385  swapvertex = permutarray[0];
12386  permutarray[0] = permutarray[1];
12387  permutarray[1] = swapvertex;
12388  }
12389 
12390  // Create the initial Delaunay tetrahedralization.
12391  initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
12392  permutarray[3]);
12393 
12394  if (b->verbose) {
12395  printf(" Incrementally inserting vertices.\n");
12396  }
12397  insertvertexflags ivf;
12398  flipconstraints fc;
12399 
12400  // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
12401  if (b->incrflip) {
12402  ivf.bowywat = 0;
12403  ivf.lawson = 1;
12404  fc.enqflag = 1;
12405  } else {
12406  ivf.bowywat = 1;
12407  ivf.lawson = 0;
12408  }
12409 
12410 
12411  for (i = 4; i < in->numberofpoints; i++) {
12412  if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
12413  setpointtype(permutarray[i], VOLVERTEX);
12414  }
12415  if (b->brio_hilbert || b->no_sort) { // -b or -b/1
12416  // Start the last updated tet.
12417  searchtet.tet = recenttet.tet;
12418  } else { // -b0
12419  // Randomly choose the starting tet for point location.
12420  searchtet.tet = NULL;
12421  }
12422  ivf.iloc = (int) OUTSIDE;
12423  // Insert the vertex.
12424  if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
12425  if (flipstack != NULL) {
12426  // Perform flip to recover Delaunayness.
12427  incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
12428  }
12429  } else {
12430  if (ivf.iloc == (int) ONVERTEX) {
12431  // The point already exists. Mark it and do nothing on it.
12432  swapvertex = org(searchtet);
12433  if (b->object != tetgenbehavior::STL) {
12434  if (!b->quiet) {
12435  printf("Warning: Point #%d is coincident with #%d. Ignored!\n",
12436  pointmark(permutarray[i]), pointmark(swapvertex));
12437  }
12438  }
12439  setpoint2ppt(permutarray[i], swapvertex);
12440  setpointtype(permutarray[i], DUPLICATEDVERTEX);
12441  dupverts++;
12442  } else if (ivf.iloc == (int) NEARVERTEX) {
12443  swapvertex = org(searchtet);
12444  if (!b->quiet) {
12445  printf("Warning: Point %d is replaced by point %d.\n",
12446  pointmark(permutarray[i]), pointmark(swapvertex));
12447  printf(" Avoid creating a very short edge (len = %g) (< %g).\n",
12448  permutarray[i][3], minedgelength);
12449  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
12450  b->epsilon);
12451  printf(" or use the option -M0/1 to avoid such replacement.\n");
12452  }
12453  // Remember it is a duplicated point.
12454  setpoint2ppt(permutarray[i], swapvertex);
12455  setpointtype(permutarray[i], DUPLICATEDVERTEX);
12456  dupverts++;
12457  } else if (ivf.iloc == (int) NONREGULAR) {
12458  // The point is non-regular. Skipped.
12459  if (b->verbose) {
12460  printf(" Point #%d is non-regular, skipped.\n",
12461  pointmark(permutarray[i]));
12462  }
12463  setpointtype(permutarray[i], NREGULARVERTEX);
12464  nonregularcount++;
12465  }
12466  }
12467  }
12468 
12469 
12470 
12471  delete [] permutarray;
12472 }
12473 
12477 
12481 
12483 // //
12484 // flipshpush() Push a facet edge into flip stack. //
12485 // //
12487 
12488 void tetgenmesh::flipshpush(face* flipedge)
12489 {
12490  badface *newflipface;
12491 
12492  newflipface = (badface *) flippool->alloc();
12493  newflipface->ss = *flipedge;
12494  newflipface->forg = sorg(*flipedge);
12495  newflipface->fdest = sdest(*flipedge);
12496  newflipface->nextitem = flipstack;
12497  flipstack = newflipface;
12498 }
12499 
12501 // //
12502 // flip22() Perform a 2-to-2 flip in surface mesh. //
12503 // //
12504 // 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and //
12505 // [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
12506 // is replaced by edge [c,d]. //
12507 // //
12509 
12510 void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
12511 {
12512  face bdedges[4], outfaces[4], infaces[4];
12513  face bdsegs[4];
12514  face checkface;
12515  point pa, pb, pc, pd;
12516  int i;
12517 
12518  pa = sorg(flipfaces[0]);
12519  pb = sdest(flipfaces[0]);
12520  pc = sapex(flipfaces[0]);
12521  pd = sapex(flipfaces[1]);
12522 
12523  if (sorg(flipfaces[1]) != pb) {
12524  sesymself(flipfaces[1]);
12525  }
12526 
12527  flip22count++;
12528 
12529  // Collect the four boundary edges.
12530  senext(flipfaces[0], bdedges[0]);
12531  senext2(flipfaces[0], bdedges[1]);
12532  senext(flipfaces[1], bdedges[2]);
12533  senext2(flipfaces[1], bdedges[3]);
12534 
12535  // Collect outer boundary faces.
12536  for (i = 0; i < 4; i++) {
12537  spivot(bdedges[i], outfaces[i]);
12538  infaces[i] = outfaces[i];
12539  sspivot(bdedges[i], bdsegs[i]);
12540  if (outfaces[i].sh != NULL) {
12541  if (isshsubseg(bdedges[i])) {
12542  spivot(infaces[i], checkface);
12543  while (checkface.sh != bdedges[i].sh) {
12544  infaces[i] = checkface;
12545  spivot(infaces[i], checkface);
12546  }
12547  }
12548  }
12549  }
12550 
12551  // The flags set in these two subfaces do not change.
12552  // Shellmark does not change.
12553  // area constraint does not change.
12554 
12555  // Transform [a,b,c] -> [c,d,b].
12556  setshvertices(flipfaces[0], pc, pd, pb);
12557  // Transform [b,a,d] -> [d,c,a].
12558  setshvertices(flipfaces[1], pd, pc, pa);
12559 
12560  // Update the point-to-subface map.
12561  if (pointtype(pa) == FREEFACETVERTEX) {
12562  setpoint2sh(pa, sencode(flipfaces[1]));
12563  }
12564  if (pointtype(pb) == FREEFACETVERTEX) {
12565  setpoint2sh(pb, sencode(flipfaces[0]));
12566  }
12567  if (pointtype(pc) == FREEFACETVERTEX) {
12568  setpoint2sh(pc, sencode(flipfaces[0]));
12569  }
12570  if (pointtype(pd) == FREEFACETVERTEX) {
12571  setpoint2sh(pd, sencode(flipfaces[0]));
12572  }
12573 
12574  // Reconnect boundary edges to outer boundary faces.
12575  for (i = 0; i < 4; i++) {
12576  if (outfaces[(3 + i) % 4].sh != NULL) {
12577  // Make sure that the subface has the ori as the segment.
12578  if (bdsegs[(3 + i) % 4].sh != NULL) {
12579  bdsegs[(3 + i) % 4].shver = 0;
12580  if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
12581  sesymself(bdedges[i]);
12582  }
12583  }
12584  sbond1(bdedges[i], outfaces[(3 + i) % 4]);
12585  sbond1(infaces[(3 + i) % 4], bdedges[i]);
12586  } else {
12587  sdissolve(bdedges[i]);
12588  }
12589  if (bdsegs[(3 + i) % 4].sh != NULL) {
12590  ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
12591  if (chkencflag & 1) {
12592  // Queue this segment for encroaching check.
12593  enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
12594  }
12595  } else {
12596  ssdissolve(bdedges[i]);
12597  }
12598  }
12599 
12600  if (chkencflag & 2) {
12601  // Queue the flipped subfaces for quality/encroaching checks.
12602  for (i = 0; i < 2; i++) {
12603  enqueuesubface(badsubfacs, &(flipfaces[i]));
12604  }
12605  }
12606 
12607  recentsh = flipfaces[0];
12608 
12609  if (flipflag) {
12610  // Put the boundary edges into flip stack.
12611  for (i = 0; i < 4; i++) {
12612  flipshpush(&(bdedges[i]));
12613  }
12614  }
12615 }
12616 
12618 // //
12619 // flip31() Remove a vertex by transforming 3-to-1 subfaces. //
12620 // //
12621 // 'flipfaces' is an array of subfaces. Its length is at least 4. On input, //
12622 // the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine //
12623 // replaces them by one face [a,b,c], it is returned in flipfaces[3]. //
12624 // //
12625 // NOTE: The three old subfaces are not deleted within this routine. They //
12626 // still hold pointers to their adjacent subfaces. These informations are //
12627 // needed by the routine 'sremovevertex()' for recovering a segment. //
12628 // The caller of this routine must delete the old subfaces after their uses. //
12629 // //
12631 
12632 void tetgenmesh::flip31(face* flipfaces, int flipflag)
12633 {
12634  face bdedges[3], outfaces[3], infaces[3];
12635  face bdsegs[3];
12636  face checkface;
12637  point pa, pb, pc;
12638  int i;
12639 
12640  pa = sdest(flipfaces[0]);
12641  pb = sdest(flipfaces[1]);
12642  pc = sdest(flipfaces[2]);
12643 
12644  flip31count++;
12645 
12646  // Collect all infos at the three boundary edges.
12647  for (i = 0; i < 3; i++) {
12648  senext(flipfaces[i], bdedges[i]);
12649  spivot(bdedges[i], outfaces[i]);
12650  infaces[i] = outfaces[i];
12651  sspivot(bdedges[i], bdsegs[i]);
12652  if (outfaces[i].sh != NULL) {
12653  if (isshsubseg(bdedges[i])) {
12654  spivot(infaces[i], checkface);
12655  while (checkface.sh != bdedges[i].sh) {
12656  infaces[i] = checkface;
12657  spivot(infaces[i], checkface);
12658  }
12659  }
12660  }
12661  } // i
12662 
12663  // Create a new subface.
12664  makeshellface(subfaces, &(flipfaces[3]));
12665  setshvertices(flipfaces[3], pa, pb,pc);
12666  setshellmark(flipfaces[3], shellmark(flipfaces[0]));
12667  if (checkconstraints) {
12668  //area = areabound(flipfaces[0]);
12669  setareabound(flipfaces[3], areabound(flipfaces[0]));
12670  }
12671  if (useinsertradius) {
12672  setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
12673  }
12674 
12675  // Update the point-to-subface map.
12676  if (pointtype(pa) == FREEFACETVERTEX) {
12677  setpoint2sh(pa, sencode(flipfaces[3]));
12678  }
12679  if (pointtype(pb) == FREEFACETVERTEX) {
12680  setpoint2sh(pb, sencode(flipfaces[3]));
12681  }
12682  if (pointtype(pc) == FREEFACETVERTEX) {
12683  setpoint2sh(pc, sencode(flipfaces[3]));
12684  }
12685 
12686  // Update the three new boundary edges.
12687  bdedges[0] = flipfaces[3]; // [a,b]
12688  senext(flipfaces[3], bdedges[1]); // [b,c]
12689  senext2(flipfaces[3], bdedges[2]); // [c,a]
12690 
12691  // Reconnect boundary edges to outer boundary faces.
12692  for (i = 0; i < 3; i++) {
12693  if (outfaces[i].sh != NULL) {
12694  // Make sure that the subface has the ori as the segment.
12695  if (bdsegs[i].sh != NULL) {
12696  bdsegs[i].shver = 0;
12697  if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
12698  sesymself(bdedges[i]);
12699  }
12700  }
12701  sbond1(bdedges[i], outfaces[i]);
12702  sbond1(infaces[i], bdedges[i]);
12703  }
12704  if (bdsegs[i].sh != NULL) {
12705  ssbond(bdedges[i], bdsegs[i]);
12706  }
12707  }
12708 
12709  recentsh = flipfaces[3];
12710 
12711  if (flipflag) {
12712  // Put the boundary edges into flip stack.
12713  for (i = 0; i < 3; i++) {
12714  flipshpush(&(bdedges[i]));
12715  }
12716  }
12717 }
12718 
12720 // //
12721 // lawsonflip() Flip non-locally Delaunay edges. //
12722 // //
12724 
12725 long tetgenmesh::lawsonflip()
12726 {
12727  badface *popface;
12728  face flipfaces[2];
12729  point pa, pb, pc, pd;
12730  REAL sign;
12731  long flipcount = 0;
12732 
12733  if (b->verbose > 2) {
12734  printf(" Lawson flip %ld edges.\n", flippool->items);
12735  }
12736 
12737  while (flipstack != (badface *) NULL) {
12738 
12739  // Pop an edge from the stack.
12740  popface = flipstack;
12741  flipfaces[0] = popface->ss;
12742  pa = popface->forg;
12743  pb = popface->fdest;
12744  flipstack = popface->nextitem; // The next top item in stack.
12745  flippool->dealloc((void *) popface);
12746 
12747  // Skip it if it is dead.
12748  if (flipfaces[0].sh[3] == NULL) continue;
12749  // Skip it if it is not the same edge as we saved.
12750  if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
12751  // Skip it if it is a subsegment.
12752  if (isshsubseg(flipfaces[0])) continue;
12753 
12754  // Get the adjacent face.
12755  spivot(flipfaces[0], flipfaces[1]);
12756  if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
12757  pc = sapex(flipfaces[0]);
12758  pd = sapex(flipfaces[1]);
12759 
12760  sign = incircle3d(pa, pb, pc, pd);
12761 
12762  if (sign < 0) {
12763  // It is non-locally Delaunay. Flip it.
12764  flip22(flipfaces, 1, 0);
12765  flipcount++;
12766  }
12767  }
12768 
12769  if (b->verbose > 2) {
12770  printf(" Performed %ld flips.\n", flipcount);
12771  }
12772 
12773  return flipcount;
12774 }
12775 
12777 // //
12778 // sinsertvertex() Insert a vertex into a triangulation of a facet. //
12779 // //
12780 // This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
12781 // 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p), //
12782 // 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a //
12783 // segment, 'cavesegshlist' returns the two new subsegments. //
12784 // //
12785 // 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
12786 // will first locate the point. It starts searching from 'searchsh' or 'rec- //
12787 // entsh' if 'searchsh' is NULL. //
12788 // //
12789 // If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert //
12790 // the vertex. Otherwise, only insert the vertex in the initial cavity. //
12791 // //
12792 // If 'iloc' is 'INSTAR', this means the cavity of this vertex was already //
12793 // provided in the list 'caveshlist'. //
12794 // //
12795 // If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
12796 // be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'. //
12797 // //
12798 // 'rflag' (rounding) is a parameter passed to slocate() function. If it is //
12799 // set, after the location of the point is found, either ONEDGE or ONFACE, //
12800 // round the result using an epsilon. //
12801 // //
12802 // NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
12803 // want to remove the new point immediately. //
12804 // //
12806 
12807 int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
12808  int iloc, int bowywat, int rflag)
12809 {
12810  face cavesh, neighsh, *parysh;
12811  face newsh, casout, casin;
12812  face checkseg;
12813  point pa, pb;
12814  enum locateresult loc = OUTSIDE;
12815  REAL sign, ori;
12816  int i, j;
12817 
12818  if (b->verbose > 2) {
12819  printf(" Insert facet point %d.\n", pointmark(insertpt));
12820  }
12821 
12822  if (bowywat == 3) {
12823  loc = INSTAR;
12824  }
12825 
12826  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12827  // A segment is going to be split, no point location.
12828  spivot(*splitseg, *searchsh);
12829  if (loc != INSTAR) loc = ONEDGE;
12830  } else {
12831  if (loc != INSTAR) loc = (enum locateresult) iloc;
12832  if (loc == OUTSIDE) {
12833  // Do point location in surface mesh.
12834  if (searchsh->sh == NULL) {
12835  *searchsh = recentsh;
12836  }
12837  // Search the vertex. An above point must be provided ('aflag' = 1).
12838  loc = slocate(insertpt, searchsh, 1, 1, rflag);
12839  }
12840  }
12841 
12842 
12843  // Form the initial sC(p).
12844  if (loc == ONFACE) {
12845  // Add the face into list (in B-W cavity).
12846  smarktest(*searchsh);
12847  caveshlist->newindex((void **) &parysh);
12848  *parysh = *searchsh;
12849  } else if (loc == ONEDGE) {
12850  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12851  splitseg->shver = 0;
12852  pa = sorg(*splitseg);
12853  } else {
12854  pa = sorg(*searchsh);
12855  }
12856  if (searchsh->sh != NULL) {
12857  // Collect all subfaces share at this edge.
12858  neighsh = *searchsh;
12859  while (1) {
12860  // Adjust the origin of its edge to be 'pa'.
12861  if (sorg(neighsh) != pa) sesymself(neighsh);
12862  // Add this face into list (in B-W cavity).
12863  smarktest(neighsh);
12864  caveshlist->newindex((void **) &parysh);
12865  *parysh = neighsh;
12866  // Add this face into face-at-splitedge list.
12867  cavesegshlist->newindex((void **) &parysh);
12868  *parysh = neighsh;
12869  // Go to the next face at the edge.
12870  spivotself(neighsh);
12871  // Stop if all faces at the edge have been visited.
12872  if (neighsh.sh == searchsh->sh) break;
12873  if (neighsh.sh == NULL) break;
12874  }
12875  } // If (not a non-dangling segment).
12876  } else if (loc == ONVERTEX) {
12877  return (int) loc;
12878  } else if (loc == OUTSIDE) {
12879  // Comment: This should only happen during the surface meshing step.
12880  // Enlarge the convex hull of the triangulation by including p.
12881  // An above point of the facet is set in 'dummypoint' to replace
12882  // orient2d tests by orient3d tests.
12883  // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
12884  // plane, and a->b is directed from left to right, p lies above a->b.
12885  // Find the right-most edge of the triangulation which is visible by p.
12886  neighsh = *searchsh;
12887  while (1) {
12888  senext2self(neighsh);
12889  spivot(neighsh, casout);
12890  if (casout.sh == NULL) {
12891  // A convex hull edge. Is it visible by p.
12892  ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
12893  if (ori < 0) {
12894  *searchsh = neighsh; // Visible, update 'searchsh'.
12895  } else {
12896  break; // 'searchsh' is the right-most visible edge.
12897  }
12898  } else {
12899  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12900  neighsh = casout;
12901  }
12902  }
12903  // Create new triangles for all visible edges of p (from right to left).
12904  casin.sh = NULL; // No adjacent face at right.
12905  pa = sorg(*searchsh);
12906  pb = sdest(*searchsh);
12907  while (1) {
12908  // Create a new subface on top of the (visible) edge.
12909  makeshellface(subfaces, &newsh);
12910  setshvertices(newsh, pb, pa, insertpt);
12911  setshellmark(newsh, shellmark(*searchsh));
12912  if (checkconstraints) {
12913  //area = areabound(*searchsh);
12914  setareabound(newsh, areabound(*searchsh));
12915  }
12916  if (useinsertradius) {
12917  setfacetindex(newsh, getfacetindex(*searchsh));
12918  }
12919  // Connect the new subface to the bottom subfaces.
12920  sbond1(newsh, *searchsh);
12921  sbond1(*searchsh, newsh);
12922  // Connect the new subface to its right-adjacent subface.
12923  if (casin.sh != NULL) {
12924  senext(newsh, casout);
12925  sbond1(casout, casin);
12926  sbond1(casin, casout);
12927  }
12928  // The left-adjacent subface has not been created yet.
12929  senext2(newsh, casin);
12930  // Add the new face into list (inside the B-W cavity).
12931  smarktest(newsh);
12932  caveshlist->newindex((void **) &parysh);
12933  *parysh = newsh;
12934  // Move to the convex hull edge at the left of 'searchsh'.
12935  neighsh = *searchsh;
12936  while (1) {
12937  senextself(neighsh);
12938  spivot(neighsh, casout);
12939  if (casout.sh == NULL) {
12940  *searchsh = neighsh;
12941  break;
12942  }
12943  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12944  neighsh = casout;
12945  }
12946  // A convex hull edge. Is it visible by p.
12947  pa = sorg(*searchsh);
12948  pb = sdest(*searchsh);
12949  ori = orient3d(pa, pb, dummypoint, insertpt);
12950  // Finish the process if p is not visible by the hull edge.
12951  if (ori >= 0) break;
12952  }
12953  } else if (loc == INSTAR) {
12954  // Under this case, the sub-cavity sC(p) has already been formed in
12955  // insertvertex().
12956  }
12957 
12958  // Form the Bowyer-Watson cavity sC(p).
12959  for (i = 0; i < caveshlist->objects; i++) {
12960  cavesh = * (face *) fastlookup(caveshlist, i);
12961  for (j = 0; j < 3; j++) {
12962  if (!isshsubseg(cavesh)) {
12963  spivot(cavesh, neighsh);
12964  if (neighsh.sh != NULL) {
12965  // The adjacent face exists.
12966  if (!smarktested(neighsh)) {
12967  if (bowywat) {
12968  if (loc == INSTAR) { // if (bowywat > 2) {
12969  // It must be a boundary edge.
12970  sign = 1;
12971  } else {
12972  // Check if this subface is connected to adjacent tet(s).
12973  if (!isshtet(neighsh)) {
12974  // Check if the subface is non-Delaunay wrt. the new pt.
12975  sign = incircle3d(sorg(neighsh), sdest(neighsh),
12976  sapex(neighsh), insertpt);
12977  } else {
12978  // It is connected to an adjacent tet. A boundary edge.
12979  sign = 1;
12980  }
12981  }
12982  if (sign < 0) {
12983  // Add the adjacent face in list (in B-W cavity).
12984  smarktest(neighsh);
12985  caveshlist->newindex((void **) &parysh);
12986  *parysh = neighsh;
12987  }
12988  } else {
12989  sign = 1; // A boundary edge.
12990  }
12991  } else {
12992  sign = -1; // Not a boundary edge.
12993  }
12994  } else {
12995  // No adjacent face. It is a hull edge.
12996  if (loc == OUTSIDE) {
12997  // It is a boundary edge if it does not contain p.
12998  if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
12999  sign = -1; // Not a boundary edge.
13000  } else {
13001  sign = 1; // A boundary edge.
13002  }
13003  } else {
13004  sign = 1; // A boundary edge.
13005  }
13006  }
13007  } else {
13008  // Do not across a segment. It is a boundary edge.
13009  sign = 1;
13010  }
13011  if (sign >= 0) {
13012  // Add a boundary edge.
13013  caveshbdlist->newindex((void **) &parysh);
13014  *parysh = cavesh;
13015  }
13016  senextself(cavesh);
13017  } // j
13018  } // i
13019 
13020 
13021  // Creating new subfaces.
13022  for (i = 0; i < caveshbdlist->objects; i++) {
13023  parysh = (face *) fastlookup(caveshbdlist, i);
13024  sspivot(*parysh, checkseg);
13025  if ((parysh->shver & 01) != 0) sesymself(*parysh);
13026  pa = sorg(*parysh);
13027  pb = sdest(*parysh);
13028  // Create a new subface.
13029  makeshellface(subfaces, &newsh);
13030  setshvertices(newsh, pa, pb, insertpt);
13031  setshellmark(newsh, shellmark(*parysh));
13032  if (checkconstraints) {
13033  //area = areabound(*parysh);
13034  setareabound(newsh, areabound(*parysh));
13035  }
13036  if (useinsertradius) {
13037  setfacetindex(newsh, getfacetindex(*parysh));
13038  }
13039  // Update the point-to-subface map.
13040  if (pointtype(pa) == FREEFACETVERTEX) {
13041  setpoint2sh(pa, sencode(newsh));
13042  }
13043  if (pointtype(pb) == FREEFACETVERTEX) {
13044  setpoint2sh(pb, sencode(newsh));
13045  }
13046  // Connect newsh to outer subfaces.
13047  spivot(*parysh, casout);
13048  if (casout.sh != NULL) {
13049  casin = casout;
13050  if (checkseg.sh != NULL) {
13051  // Make sure that newsh has the right ori at this segment.
13052  checkseg.shver = 0;
13053  if (sorg(newsh) != sorg(checkseg)) {
13054  sesymself(newsh);
13055  sesymself(*parysh); // This side should also be inverse.
13056  }
13057  spivot(casin, neighsh);
13058  while (neighsh.sh != parysh->sh) {
13059  casin = neighsh;
13060  spivot(casin, neighsh);
13061  }
13062  }
13063  sbond1(newsh, casout);
13064  sbond1(casin, newsh);
13065  }
13066  if (checkseg.sh != NULL) {
13067  ssbond(newsh, checkseg);
13068  }
13069  // Connect oldsh <== newsh (for connecting adjacent new subfaces).
13070  // *parysh and newsh point to the same edge and the same ori.
13071  sbond1(*parysh, newsh);
13072  }
13073 
13074  if (newsh.sh != NULL) {
13075  // Set a handle for searching.
13076  recentsh = newsh;
13077  }
13078 
13079  // Update the point-to-subface map.
13080  if (pointtype(insertpt) == FREEFACETVERTEX) {
13081  setpoint2sh(insertpt, sencode(newsh));
13082  }
13083 
13084  // Connect adjacent new subfaces together.
13085  for (i = 0; i < caveshbdlist->objects; i++) {
13086  // Get an old subface at edge [a, b].
13087  parysh = (face *) fastlookup(caveshbdlist, i);
13088  spivot(*parysh, newsh); // The new subface [a, b, p].
13089  senextself(newsh); // At edge [b, p].
13090  spivot(newsh, neighsh);
13091  if (neighsh.sh == NULL) {
13092  // Find the adjacent new subface at edge [b, p].
13093  pb = sdest(*parysh);
13094  neighsh = *parysh;
13095  while (1) {
13096  senextself(neighsh);
13097  spivotself(neighsh);
13098  if (neighsh.sh == NULL) break;
13099  if (!smarktested(neighsh)) break;
13100  if (sdest(neighsh) != pb) sesymself(neighsh);
13101  }
13102  if (neighsh.sh != NULL) {
13103  // Now 'neighsh' is a new subface at edge [b, #].
13104  if (sorg(neighsh) != pb) sesymself(neighsh);
13105  senext2self(neighsh); // Go to the open edge [p, b].
13106  sbond(newsh, neighsh);
13107  }
13108  }
13109  spivot(*parysh, newsh); // The new subface [a, b, p].
13110  senext2self(newsh); // At edge [p, a].
13111  spivot(newsh, neighsh);
13112  if (neighsh.sh == NULL) {
13113  // Find the adjacent new subface at edge [p, a].
13114  pa = sorg(*parysh);
13115  neighsh = *parysh;
13116  while (1) {
13117  senext2self(neighsh);
13118  spivotself(neighsh);
13119  if (neighsh.sh == NULL) break;
13120  if (!smarktested(neighsh)) break;
13121  if (sorg(neighsh) != pa) sesymself(neighsh);
13122  }
13123  if (neighsh.sh != NULL) {
13124  // Now 'neighsh' is a new subface at edge [#, a].
13125  if (sdest(neighsh) != pa) sesymself(neighsh);
13126  senextself(neighsh); // Go to the open edge [a, p].
13127  sbond(newsh, neighsh);
13128  }
13129  }
13130  }
13131 
13132  if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
13133  || (cavesegshlist->objects > 0l)) {
13134  // An edge is being split. We distinguish two cases:
13135  // (1) the edge is not on the boundary of the cavity;
13136  // (2) the edge is on the boundary of the cavity.
13137  // In case (2), the edge is either a segment or a hull edge. There are
13138  // degenerated new faces in the cavity. They must be removed.
13139  face aseg, bseg, aoutseg, boutseg;
13140 
13141  for (i = 0; i < cavesegshlist->objects; i++) {
13142  // Get the saved old subface.
13143  parysh = (face *) fastlookup(cavesegshlist, i);
13144  // Get a possible new degenerated subface.
13145  spivot(*parysh, cavesh);
13146  if (sapex(cavesh) == insertpt) {
13147  // Found a degenerated new subface, i.e., case (2).
13148  if (cavesegshlist->objects > 1) {
13149  // There are more than one subface share at this edge.
13150  j = (i + 1) % (int) cavesegshlist->objects;
13151  parysh = (face *) fastlookup(cavesegshlist, j);
13152  spivot(*parysh, neighsh);
13153  // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
13154  if (sorg(neighsh) != sorg(cavesh)) {
13155  sesymself(neighsh);
13156  }
13157  // Connect adjacent faces at two other edges of cavesh and neighsh.
13158  // As a result, the two degenerated new faces are squeezed from the
13159  // new triangulation of the cavity. Note that the squeezed faces
13160  // still hold the adjacent informations which will be used in
13161  // re-connecting subsegments (if they exist).
13162  for (j = 0; j < 2; j++) {
13163  senextself(cavesh);
13164  senextself(neighsh);
13165  spivot(cavesh, newsh);
13166  spivot(neighsh, casout);
13167  sbond1(newsh, casout); // newsh <- casout.
13168  }
13169  } else {
13170  // There is only one subface containing this edge [a,b]. Squeeze the
13171  // degenerated new face [a,b,c] by disconnecting it from its two
13172  // adjacent subfaces at edges [b,c] and [c,a]. Note that the face
13173  // [a,b,c] still hold the connection to them.
13174  for (j = 0; j < 2; j++) {
13175  senextself(cavesh);
13176  spivot(cavesh, newsh);
13177  sdissolve(newsh);
13178  }
13179  }
13180  //recentsh = newsh;
13181  // Update the point-to-subface map.
13182  if (pointtype(insertpt) == FREEFACETVERTEX) {
13183  setpoint2sh(insertpt, sencode(newsh));
13184  }
13185  }
13186  }
13187 
13188  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
13189  if (loc != INSTAR) { // if (bowywat < 3) {
13190  smarktest(*splitseg); // Mark it as being processed.
13191  }
13192 
13193  aseg = *splitseg;
13194  pa = sorg(*splitseg);
13195  pb = sdest(*splitseg);
13196 
13197  // Insert the new point p.
13198  makeshellface(subsegs, &aseg);
13199  makeshellface(subsegs, &bseg);
13200 
13201  setshvertices(aseg, pa, insertpt, NULL);
13202  setshvertices(bseg, insertpt, pb, NULL);
13203  setshellmark(aseg, shellmark(*splitseg));
13204  setshellmark(bseg, shellmark(*splitseg));
13205  if (checkconstraints) {
13206  setareabound(aseg, areabound(*splitseg));
13207  setareabound(bseg, areabound(*splitseg));
13208  }
13209  if (useinsertradius) {
13210  setfacetindex(aseg, getfacetindex(*splitseg));
13211  setfacetindex(bseg, getfacetindex(*splitseg));
13212  }
13213 
13214  // Connect [#, a]<->[a, p].
13215  senext2(*splitseg, boutseg); // Temporarily use boutseg.
13216  spivotself(boutseg);
13217  if (boutseg.sh != NULL) {
13218  senext2(aseg, aoutseg);
13219  sbond(boutseg, aoutseg);
13220  }
13221  // Connect [p, b]<->[b, #].
13222  senext(*splitseg, aoutseg);
13223  spivotself(aoutseg);
13224  if (aoutseg.sh != NULL) {
13225  senext(bseg, boutseg);
13226  sbond(boutseg, aoutseg);
13227  }
13228  // Connect [a, p] <-> [p, b].
13229  senext(aseg, aoutseg);
13230  senext2(bseg, boutseg);
13231  sbond(aoutseg, boutseg);
13232 
13233  // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
13234  // Although the degenerated new faces have been squeezed. They still
13235  // hold the connections to the actual new faces.
13236  for (i = 0; i < cavesegshlist->objects; i++) {
13237  parysh = (face *) fastlookup(cavesegshlist, i);
13238  spivot(*parysh, neighsh);
13239  // neighsh is a degenerated new face.
13240  if (sorg(neighsh) != pa) {
13241  sesymself(neighsh);
13242  }
13243  senext2(neighsh, newsh);
13244  spivotself(newsh); // The edge [p, a] in newsh
13245  ssbond(newsh, aseg);
13246  senext(neighsh, newsh);
13247  spivotself(newsh); // The edge [b, p] in newsh
13248  ssbond(newsh, bseg);
13249  }
13250 
13251 
13252  // Let the point remember the segment it lies on.
13253  if (pointtype(insertpt) == FREESEGVERTEX) {
13254  setpoint2sh(insertpt, sencode(aseg));
13255  }
13256  // Update the point-to-seg map.
13257  if (pointtype(pa) == FREESEGVERTEX) {
13258  setpoint2sh(pa, sencode(aseg));
13259  }
13260  if (pointtype(pb) == FREESEGVERTEX) {
13261  setpoint2sh(pb, sencode(bseg));
13262  }
13263  } // if ((splitseg != NULL) && (splitseg->sh != NULL))
13264 
13265  // Delete all degenerated new faces.
13266  for (i = 0; i < cavesegshlist->objects; i++) {
13267  parysh = (face *) fastlookup(cavesegshlist, i);
13268  spivotself(*parysh);
13269  if (sapex(*parysh) == insertpt) {
13270  shellfacedealloc(subfaces, parysh->sh);
13271  }
13272  }
13273  cavesegshlist->restart();
13274 
13275  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
13276  // Return the two new subsegments (for further process).
13277  // Re-use 'cavesegshlist'.
13278  cavesegshlist->newindex((void **) &parysh);
13279  *parysh = aseg;
13280  cavesegshlist->newindex((void **) &parysh);
13281  *parysh = bseg;
13282  }
13283  } // if (loc == ONEDGE)
13284 
13285 
13286  return (int) loc;
13287 }
13288 
13290 // //
13291 // sremovevertex() Remove a vertex from the surface mesh. //
13292 // //
13293 // 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
13294 // a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a //
13295 // facet vertex, and the origin of 'parentsh' is p. //
13296 // //
13297 // Within each facet, we first use a sequence of 2-to-2 flips to flip any //
13298 // edge at p, finally use a 3-to-1 flip to remove p. //
13299 // //
13300 // All new created subfaces are returned in the global array 'caveshbdlist'. //
13301 // The new segment (when p is on segment) is returned in 'parentseg'. //
13302 // //
13303 // If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay- //
13304 // ness after p is removed. //
13305 // //
13307 
13308 int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
13309  int lawson)
13310 {
13311  face flipfaces[4], spinsh, *parysh;
13312  point pa, pb, pc, pd;
13313  REAL ori1, ori2;
13314  int it, i, j;
13315 
13316  if (parentseg != NULL) {
13317  // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
13318  // where 'parentseg' should be [p,b]. Find the segment [a,p].
13319  face startsh, neighsh, nextsh;
13320  face abseg, prevseg, checkseg;
13321  face adjseg1, adjseg2;
13322  face fakesh;
13323  senext2(*parentseg, prevseg);
13324  spivotself(prevseg);
13325  prevseg.shver = 0;
13326  // Restore the original segment [a,b].
13327  pa = sorg(prevseg);
13328  pb = sdest(*parentseg);
13329  if (b->verbose > 2) {
13330  printf(" Remove vertex %d from segment [%d, %d].\n",
13331  pointmark(delpt), pointmark(pa), pointmark(pb));
13332  }
13333  makeshellface(subsegs, &abseg);
13334  setshvertices(abseg, pa, pb, NULL);
13335  setshellmark(abseg, shellmark(*parentseg));
13336  if (checkconstraints) {
13337  setareabound(abseg, areabound(*parentseg));
13338  }
13339  if (useinsertradius) {
13340  setfacetindex(abseg, getfacetindex(*parentseg));
13341  }
13342  // Connect [#, a]<->[a, b].
13343  senext2(prevseg, adjseg1);
13344  spivotself(adjseg1);
13345  if (adjseg1.sh != NULL) {
13346  adjseg1.shver = 0;
13347  senextself(adjseg1);
13348  senext2(abseg, adjseg2);
13349  sbond(adjseg1, adjseg2);
13350  }
13351  // Connect [a, b]<->[b, #].
13352  senext(*parentseg, adjseg1);
13353  spivotself(adjseg1);
13354  if (adjseg1.sh != NULL) {
13355  adjseg1.shver = 0;
13356  senext2self(adjseg1);
13357  senext(abseg, adjseg2);
13358  sbond(adjseg1, adjseg2);
13359  }
13360  // Update the point-to-segment map.
13361  setpoint2sh(pa, sencode(abseg));
13362  setpoint2sh(pb, sencode(abseg));
13363 
13364  // Get the faces in face ring at segment [p, b].
13365  // Re-use array 'caveshlist'.
13366  spivot(*parentseg, *parentsh);
13367  if (parentsh->sh != NULL) {
13368  spinsh = *parentsh;
13369  while (1) {
13370  // Save this face in list.
13371  caveshlist->newindex((void **) &parysh);
13372  *parysh = spinsh;
13373  // Go to the next face in the ring.
13374  spivotself(spinsh);
13375  if (spinsh.sh == NULL) {
13376  break; // It is possible there is only one facet.
13377  }
13378  if (spinsh.sh == parentsh->sh) break;
13379  }
13380  }
13381 
13382  // Create the face ring of the new segment [a,b]. Each face in the ring
13383  // is [a,b,p] (degenerated!). It will be removed (automatically).
13384  for (i = 0; i < caveshlist->objects; i++) {
13385  parysh = (face *) fastlookup(caveshlist, i);
13386  startsh = *parysh;
13387  if (sorg(startsh) != delpt) {
13388  sesymself(startsh);
13389  }
13390  // startsh is [p, b, #1], find the subface [a, p, #2].
13391  neighsh = startsh;
13392  while (1) {
13393  senext2self(neighsh);
13394  sspivot(neighsh, checkseg);
13395  if (checkseg.sh != NULL) {
13396  // It must be the segment [a, p].
13397  break;
13398  }
13399  spivotself(neighsh);
13400  if (sorg(neighsh) != delpt) sesymself(neighsh);
13401  }
13402  // Now neighsh is [a, p, #2].
13403  if (neighsh.sh != startsh.sh) {
13404  // Detach the two subsegments [a,p] and [p,b] from subfaces.
13405  ssdissolve(startsh);
13406  ssdissolve(neighsh);
13407  // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
13408  // new segment [a,b]; (2) connect to the two adjacent subfaces
13409  // [p,b,#] and [a,p,#].
13410  makeshellface(subfaces, &fakesh);
13411  setshvertices(fakesh, pa, pb, delpt);
13412  setshellmark(fakesh, shellmark(startsh));
13413  // Connect fakesh to the segment [a,b].
13414  ssbond(fakesh, abseg);
13415  // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
13416  senext(fakesh, nextsh);
13417  sbond(nextsh, startsh);
13418  senext2(fakesh, nextsh);
13419  sbond(nextsh, neighsh);
13420  smarktest(fakesh); // Mark it as faked.
13421  } else {
13422  // Special case. There exists already a degenerated face [a,b,p]!
13423  // There is no need to create a faked subface here.
13424  senext2self(neighsh); // [a,b,p]
13425  // Since we will re-connect the face ring using the faked subfaces.
13426  // We put the adjacent face of [a,b,p] to the list.
13427  spivot(neighsh, startsh); // The original adjacent subface.
13428  if (sorg(startsh) != pa) sesymself(startsh);
13429  sdissolve(startsh);
13430  // Connect fakesh to the segment [a,b].
13431  ssbond(startsh, abseg);
13432  fakesh = startsh; // Do not mark it!
13433  // Delete the degenerated subface.
13434  shellfacedealloc(subfaces, neighsh.sh);
13435  }
13436  // Save the fakesh in list (for re-creating the face ring).
13437  cavesegshlist->newindex((void **) &parysh);
13438  *parysh = fakesh;
13439  } // i
13440  caveshlist->restart();
13441 
13442  // Re-create the face ring.
13443  if (cavesegshlist->objects > 1) {
13444  for (i = 0; i < cavesegshlist->objects; i++) {
13445  parysh = (face *) fastlookup(cavesegshlist, i);
13446  fakesh = *parysh;
13447  // Get the next face in the ring.
13448  j = (i + 1) % cavesegshlist->objects;
13449  parysh = (face *) fastlookup(cavesegshlist, j);
13450  nextsh = *parysh;
13451  sbond1(fakesh, nextsh);
13452  }
13453  }
13454 
13455  // Delete the two subsegments containing p.
13456  shellfacedealloc(subsegs, parentseg->sh);
13457  shellfacedealloc(subsegs, prevseg.sh);
13458  // Return the new segment.
13459  *parentseg = abseg;
13460  } else {
13461  // p is inside the surface.
13462  if (b->verbose > 2) {
13463  printf(" Remove vertex %d from surface.\n", pointmark(delpt));
13464  }
13465  // Let 'delpt' be its apex.
13466  senextself(*parentsh);
13467  // For unifying the code, we add parentsh to list.
13468  cavesegshlist->newindex((void **) &parysh);
13469  *parysh = *parentsh;
13470  }
13471 
13472  // Remove the point (p).
13473 
13474  for (it = 0; it < cavesegshlist->objects; it++) {
13475  parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
13476  senextself(*parentsh); // [b,p,a].
13477  spivotself(*parentsh);
13478  if (sorg(*parentsh) != delpt) sesymself(*parentsh);
13479  // now parentsh is [p,b,#].
13480  if (sorg(*parentsh) != delpt) {
13481  // The vertex has already been removed in above special case.
13482  continue;
13483  }
13484 
13485  while (1) {
13486  // Initialize the flip edge list. Re-use 'caveshlist'.
13487  spinsh = *parentsh; // [p, b, #]
13488  while (1) {
13489  caveshlist->newindex((void **) &parysh);
13490  *parysh = spinsh;
13491  senext2self(spinsh);
13492  spivotself(spinsh);
13493  if (spinsh.sh == parentsh->sh) break;
13494  if (sorg(spinsh) != delpt) sesymself(spinsh);
13495  } // while (1)
13496 
13497  if (caveshlist->objects == 3) {
13498  // Delete the point by a 3-to-1 flip.
13499  for (i = 0; i < 3; i++) {
13500  parysh = (face *) fastlookup(caveshlist, i);
13501  flipfaces[i] = *parysh;
13502  }
13503  flip31(flipfaces, lawson);
13504  for (i = 0; i < 3; i++) {
13505  shellfacedealloc(subfaces, flipfaces[i].sh);
13506  }
13507  caveshlist->restart();
13508  // Save the new subface.
13509  caveshbdlist->newindex((void **) &parysh);
13510  *parysh = flipfaces[3];
13511  // The vertex is removed.
13512  break;
13513  }
13514 
13515  // Search an edge to flip.
13516  for (i = 0; i < caveshlist->objects; i++) {
13517  parysh = (face *) fastlookup(caveshlist, i);
13518  flipfaces[0] = *parysh;
13519  spivot(flipfaces[0], flipfaces[1]);
13520  if (sorg(flipfaces[0]) != sdest(flipfaces[1]))
13521  sesymself(flipfaces[1]);
13522  // Skip this edge if it belongs to a faked subface.
13523  if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
13524  pa = sorg(flipfaces[0]);
13525  pb = sdest(flipfaces[0]);
13526  pc = sapex(flipfaces[0]);
13527  pd = sapex(flipfaces[1]);
13528  calculateabovepoint4(pa, pb, pc, pd);
13529  // Check if a 2-to-2 flip is possible.
13530  ori1 = orient3d(pc, pd, dummypoint, pa);
13531  ori2 = orient3d(pc, pd, dummypoint, pb);
13532  if (ori1 * ori2 < 0) {
13533  // A 2-to-2 flip is found.
13534  flip22(flipfaces, lawson, 0);
13535  // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
13536  // changed. The 'flipfaces[1]' contains p as its apex.
13537  senext2(flipfaces[1], *parentsh);
13538  // Save the new subface.
13539  caveshbdlist->newindex((void **) &parysh);
13540  *parysh = flipfaces[0];
13541  break;
13542  }
13543  } //
13544  } // i
13545 
13546  if (i == caveshlist->objects) {
13547  // Do a flip22 and a flip31 to remove p.
13548  parysh = (face *) fastlookup(caveshlist, 0);
13549  flipfaces[0] = *parysh;
13550  spivot(flipfaces[0], flipfaces[1]);
13551  if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
13552  sesymself(flipfaces[1]);
13553  }
13554  flip22(flipfaces, lawson, 0);
13555  senext2(flipfaces[1], *parentsh);
13556  // Save the new subface.
13557  caveshbdlist->newindex((void **) &parysh);
13558  *parysh = flipfaces[0];
13559  }
13560 
13561  // The edge list at p are changed.
13562  caveshlist->restart();
13563  } // while (1)
13564 
13565  } // it
13566 
13567  cavesegshlist->restart();
13568 
13569  if (b->verbose > 2) {
13570  printf(" Created %ld new subfaces.\n", caveshbdlist->objects);
13571  }
13572 
13573 
13574  if (lawson) {
13575  lawsonflip();
13576  }
13577 
13578  return 0;
13579 }
13580 
13582 // //
13583 // slocate() Locate a point in a surface triangulation. //
13584 // //
13585 // Staring the search from 'searchsh'(it should not be NULL). Perform a line //
13586 // walk search for a subface containing the point (p). //
13587 // //
13588 // If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies //
13589 // above the 'searchsh' in its current orientation. The test if c is CCW to //
13590 // the line a->b can be done by the test if c is below the oriented plane //
13591 // a->b->dummypoint. //
13592 // //
13593 // If 'cflag' is not TRUE, the triangulation may not be convex. Stop search //
13594 // when a segment is met and return OUTSIDE. //
13595 // //
13596 // If 'rflag' (rounding) is set, after the location of the point is found, //
13597 // either ONEDGE or ONFACE, round the result using an epsilon. //
13598 // //
13599 // The returned value indicates the following cases: //
13600 // - ONVERTEX, p is the origin of 'searchsh'. //
13601 // - ONEDGE, p lies on the edge of 'searchsh'. //
13602 // - ONFACE, p lies in the interior of 'searchsh'. //
13603 // - OUTSIDE, p lies outside of the triangulation, p is on the left-hand //
13604 // side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW. //
13605 // //
13607 
13608 enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
13609  face* searchsh, int aflag, int cflag, int rflag)
13610 {
13611  face neighsh;
13612  point pa, pb, pc;
13613  enum locateresult loc;
13614  enum {MOVE_BC, MOVE_CA} nextmove;
13615  REAL ori, ori_bc, ori_ca;
13616  int i;
13617 
13618  pa = sorg(*searchsh);
13619  pb = sdest(*searchsh);
13620  pc = sapex(*searchsh);
13621 
13622  if (!aflag) {
13623  // No above point is given. Calculate an above point for this facet.
13624  calculateabovepoint4(pa, pb, pc, searchpt);
13625  }
13626 
13627  // 'dummypoint' is given. Make sure it is above [a,b,c]
13628  ori = orient3d(pa, pb, pc, dummypoint);
13629  if (ori > 0) {
13630  sesymself(*searchsh); // Reverse the face orientation.
13631  } else if (ori == 0.0) {
13632  // This case should not happen theoretically. But...
13633  return UNKNOWN;
13634  }
13635 
13636  // Find an edge of the face s.t. p lies on its right-hand side (CCW).
13637  for (i = 0; i < 3; i++) {
13638  pa = sorg(*searchsh);
13639  pb = sdest(*searchsh);
13640  ori = orient3d(pa, pb, dummypoint, searchpt);
13641  if (ori > 0) break;
13642  senextself(*searchsh);
13643  }
13644  if (i == 3) {
13645  return UNKNOWN;
13646  }
13647 
13648  pc = sapex(*searchsh);
13649 
13650  if (pc == searchpt) {
13651  senext2self(*searchsh);
13652  return ONVERTEX;
13653  }
13654 
13655  while (1) {
13656 
13657  ori_bc = orient3d(pb, pc, dummypoint, searchpt);
13658  ori_ca = orient3d(pc, pa, dummypoint, searchpt);
13659 
13660  if (ori_bc < 0) {
13661  if (ori_ca < 0) { // (--)
13662  // Any of the edges is a viable move.
13663  if (randomnation(2)) {
13664  nextmove = MOVE_CA;
13665  } else {
13666  nextmove = MOVE_BC;
13667  }
13668  } else { // (-#)
13669  // Edge [b, c] is viable.
13670  nextmove = MOVE_BC;
13671  }
13672  } else {
13673  if (ori_ca < 0) { // (#-)
13674  // Edge [c, a] is viable.
13675  nextmove = MOVE_CA;
13676  } else {
13677  if (ori_bc > 0) {
13678  if (ori_ca > 0) { // (++)
13679  loc = ONFACE; // Inside [a, b, c].
13680  break;
13681  } else { // (+0)
13682  senext2self(*searchsh); // On edge [c, a].
13683  loc = ONEDGE;
13684  break;
13685  }
13686  } else { // ori_bc == 0
13687  if (ori_ca > 0) { // (0+)
13688  senextself(*searchsh); // On edge [b, c].
13689  loc = ONEDGE;
13690  break;
13691  } else { // (00)
13692  // p is coincident with vertex c.
13693  senext2self(*searchsh);
13694  return ONVERTEX;
13695  }
13696  }
13697  }
13698  }
13699 
13700  // Move to the next face.
13701  if (nextmove == MOVE_BC) {
13702  senextself(*searchsh);
13703  } else {
13704  senext2self(*searchsh);
13705  }
13706  if (!cflag) {
13707  // NON-convex case. Check if we will cross a boundary.
13708  if (isshsubseg(*searchsh)) {
13709  return ENCSEGMENT;
13710  }
13711  }
13712  spivot(*searchsh, neighsh);
13713  if (neighsh.sh == NULL) {
13714  return OUTSIDE; // A hull edge.
13715  }
13716  // Adjust the edge orientation.
13717  if (sorg(neighsh) != sdest(*searchsh)) {
13718  sesymself(neighsh);
13719  }
13720 
13721  // Update the newly discovered face and its endpoints.
13722  *searchsh = neighsh;
13723  pa = sorg(*searchsh);
13724  pb = sdest(*searchsh);
13725  pc = sapex(*searchsh);
13726 
13727  if (pc == searchpt) {
13728  senext2self(*searchsh);
13729  return ONVERTEX;
13730  }
13731 
13732  } // while (1)
13733 
13734  // assert(loc == ONFACE || loc == ONEDGE);
13735 
13736 
13737  if (rflag) {
13738  // Round the locate result before return.
13739  REAL n[3], area_abc, area_abp, area_bcp, area_cap;
13740 
13741  pa = sorg(*searchsh);
13742  pb = sdest(*searchsh);
13743  pc = sapex(*searchsh);
13744 
13745  facenormal(pa, pb, pc, n, 1, NULL);
13746  area_abc = sqrt(dot(n, n));
13747 
13748  facenormal(pb, pc, searchpt, n, 1, NULL);
13749  area_bcp = sqrt(dot(n, n));
13750  if ((area_bcp / area_abc) < b->epsilon) {
13751  area_bcp = 0; // Rounding.
13752  }
13753 
13754  facenormal(pc, pa, searchpt, n, 1, NULL);
13755  area_cap = sqrt(dot(n, n));
13756  if ((area_cap / area_abc) < b->epsilon) {
13757  area_cap = 0; // Rounding
13758  }
13759 
13760  if ((loc == ONFACE) || (loc == OUTSIDE)) {
13761  facenormal(pa, pb, searchpt, n, 1, NULL);
13762  area_abp = sqrt(dot(n, n));
13763  if ((area_abp / area_abc) < b->epsilon) {
13764  area_abp = 0; // Rounding
13765  }
13766  } else { // loc == ONEDGE
13767  area_abp = 0;
13768  }
13769 
13770  if (area_abp == 0) {
13771  if (area_bcp == 0) {
13772  senextself(*searchsh);
13773  loc = ONVERTEX; // p is close to b.
13774  } else {
13775  if (area_cap == 0) {
13776  loc = ONVERTEX; // p is close to a.
13777  } else {
13778  loc = ONEDGE; // p is on edge [a,b].
13779  }
13780  }
13781  } else if (area_bcp == 0) {
13782  if (area_cap == 0) {
13783  senext2self(*searchsh);
13784  loc = ONVERTEX; // p is close to c.
13785  } else {
13786  senextself(*searchsh);
13787  loc = ONEDGE; // p is on edge [b,c].
13788  }
13789  } else if (area_cap == 0) {
13790  senext2self(*searchsh);
13791  loc = ONEDGE; // p is on edge [c,a].
13792  } else {
13793  loc = ONFACE; // p is on face [a,b,c].
13794  }
13795  } // if (rflag)
13796 
13797  return loc;
13798 }
13799 
13801 // //
13802 // sscoutsegment() Look for a segment in the surface triangulation. //
13803 // //
13804 // The segment is given by the origin of 'searchsh' and 'endpt'. //
13805 // //
13806 // If an edge in T is found matching this segment, the segment is "locked" //
13807 // in T at the edge. Otherwise, flip the first edge in T that the segment //
13808 // crosses. Continue the search from the flipped face. //
13809 // //
13810 // This routine uses 'orisent3d' to determine the search direction. It uses //
13811 // 'dummypoint' as the 'lifted point' in 3d, and it assumes that it (dummy- //
13812 // point) lies above the 'searchsh' (w.r.t the Right-hand rule). //
13813 // //
13815 
13816 enum tetgenmesh::interresult tetgenmesh::sscoutsegment(face *searchsh,
13817  point endpt, int insertsegflag, int reporterrorflag, int chkencflag)
13818 {
13819  face flipshs[2], neighsh;
13820  point startpt, pa, pb, pc, pd;
13821  enum interresult dir;
13822  enum {MOVE_AB, MOVE_CA} nextmove;
13823  REAL ori_ab, ori_ca, len;
13824 
13825  pc = NULL; // Avoid warnings from MSVC
13826  // The origin of 'searchsh' is fixed.
13827  startpt = sorg(*searchsh);
13828  nextmove = MOVE_AB; // Avoid compiler warning.
13829 
13830  if (b->verbose > 2) {
13831  printf(" Scout segment (%d, %d).\n", pointmark(startpt),
13832  pointmark(endpt));
13833  }
13834  len = distance(startpt, endpt);
13835 
13836  // Search an edge in 'searchsh' on the path of this segment.
13837  while (1) {
13838 
13839  pb = sdest(*searchsh);
13840  if (pb == endpt) {
13841  dir = SHAREEDGE; // Found!
13842  break;
13843  }
13844 
13845  pc = sapex(*searchsh);
13846  if (pc == endpt) {
13847  senext2self(*searchsh);
13848  sesymself(*searchsh);
13849  dir = SHAREEDGE; // Found!
13850  break;
13851  }
13852 
13853 
13854  // Round the results.
13855  if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
13856  ori_ab = 0.0;
13857  } else {
13858  ori_ab = orient3d(startpt, pb, dummypoint, endpt);
13859  }
13860  if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
13861  ori_ca = 0.0;
13862  } else {
13863  ori_ca = orient3d(pc, startpt, dummypoint, endpt);
13864  }
13865 
13866  if (ori_ab < 0) {
13867  if (ori_ca < 0) { // (--)
13868  // Both sides are viable moves.
13869  if (randomnation(2)) {
13870  nextmove = MOVE_CA;
13871  } else {
13872  nextmove = MOVE_AB;
13873  }
13874  } else { // (-#)
13875  nextmove = MOVE_AB;
13876  }
13877  } else {
13878  if (ori_ca < 0) { // (#-)
13879  nextmove = MOVE_CA;
13880  } else {
13881  if (ori_ab > 0) {
13882  if (ori_ca > 0) { // (++)
13883  // The segment intersects with edge [b, c].
13884  dir = ACROSSEDGE;
13885  break;
13886  } else { // (+0)
13887  // The segment collinear with edge [c, a].
13888  senext2self(*searchsh);
13889  sesymself(*searchsh);
13890  dir = ACROSSVERT;
13891  break;
13892  }
13893  } else {
13894  if (ori_ca > 0) { // (0+)
13895  // The segment is collinear with edge [a, b].
13896  dir = ACROSSVERT;
13897  break;
13898  } else { // (00)
13899  // startpt == endpt. Not possible.
13900  terminatetetgen(this, 2);
13901  }
13902  }
13903  }
13904  }
13905 
13906  // Move 'searchsh' to the next face, keep the origin unchanged.
13907  if (nextmove == MOVE_AB) {
13908  if (chkencflag) {
13909  // Do not cross boundary.
13910  if (isshsubseg(*searchsh)) {
13911  return ACROSSEDGE; // ACROSS_SEG
13912  }
13913  }
13914  spivot(*searchsh, neighsh);
13915  if (neighsh.sh != NULL) {
13916  if (sorg(neighsh) != pb) sesymself(neighsh);
13917  senext(neighsh, *searchsh);
13918  } else {
13919  // This side (startpt->pb) is outside. It is caused by rounding error.
13920  // Try the next side, i.e., (pc->startpt).
13921  senext2(*searchsh, neighsh);
13922  if (chkencflag) {
13923  // Do not cross boundary.
13924  if (isshsubseg(neighsh)) {
13925  *searchsh = neighsh;
13926  return ACROSSEDGE; // ACROSS_SEG
13927  }
13928  }
13929  spivotself(neighsh);
13930  if (sdest(neighsh) != pc) sesymself(neighsh);
13931  *searchsh = neighsh;
13932  }
13933  } else { // MOVE_CA
13934  senext2(*searchsh, neighsh);
13935  if (chkencflag) {
13936  // Do not cross boundary.
13937  if (isshsubseg(neighsh)) {
13938  *searchsh = neighsh;
13939  return ACROSSEDGE; // ACROSS_SEG
13940  }
13941  }
13942  spivotself(neighsh);
13943  if (neighsh.sh != NULL) {
13944  if (sdest(neighsh) != pc) sesymself(neighsh);
13945  *searchsh = neighsh;
13946  } else {
13947  // The same reason as above.
13948  // Try the next side, i.e., (startpt->pb).
13949  if (chkencflag) {
13950  // Do not cross boundary.
13951  if (isshsubseg(*searchsh)) {
13952  return ACROSSEDGE; // ACROSS_SEG
13953  }
13954  }
13955  spivot(*searchsh, neighsh);
13956  if (sorg(neighsh) != pb) sesymself(neighsh);
13957  senext(neighsh, *searchsh);
13958  }
13959  }
13960  } // while
13961 
13962  if (dir == SHAREEDGE) {
13963  if (insertsegflag) {
13964  // Insert the segment into the triangulation.
13965  face newseg;
13966  makeshellface(subsegs, &newseg);
13967  setshvertices(newseg, startpt, endpt, NULL);
13968  // Set the default segment marker.
13969  setshellmark(newseg, -1);
13970  ssbond(*searchsh, newseg);
13971  spivot(*searchsh, neighsh);
13972  if (neighsh.sh != NULL) {
13973  ssbond(neighsh, newseg);
13974  }
13975  }
13976  return dir;
13977  }
13978 
13979  if (dir == ACROSSVERT) {
13980  // A point is found collinear with this segment.
13981  if (reporterrorflag) {
13982  point pp = sdest(*searchsh);
13983  printf("PLC Error: A vertex lies in a segment in facet #%d.\n",
13984  shellmark(*searchsh));
13985  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
13986  printf(" Segment: [%d, %d]\n", pointmark(startpt), pointmark(endpt));
13987  }
13988  return dir;
13989  }
13990 
13991  if (dir == ACROSSEDGE) {
13992  // Edge [b, c] intersects with the segment.
13993  senext(*searchsh, flipshs[0]);
13994  if (isshsubseg(flipshs[0])) {
13995  if (reporterrorflag) {
13996  REAL P[3], Q[3], tp = 0, tq = 0;
13997  linelineint(startpt, endpt, pb, pc, P, Q, &tp, &tq);
13998  printf("PLC Error: Two segments intersect at point (%g,%g,%g),",
13999  P[0], P[1], P[2]);
14000  printf(" in facet #%d.\n", shellmark(*searchsh));
14001  printf(" Segment 1: [%d, %d]\n", pointmark(pb), pointmark(pc));
14002  printf(" Segment 2: [%d, %d]\n", pointmark(startpt),pointmark(endpt));
14003  }
14004  return dir; // ACROSS_SEG
14005  }
14006  // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
14007  spivot(flipshs[0], flipshs[1]);
14008  if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
14009  flip22(flipshs, 1, 0);
14010  // The flip may create an inverted triangle, check it.
14011  pa = sapex(flipshs[1]);
14012  pb = sapex(flipshs[0]);
14013  pc = sorg(flipshs[0]);
14014  pd = sdest(flipshs[0]);
14015  // Check if pa and pb are on the different sides of [pc, pd].
14016  // Re-use ori_ab, ori_ca for the tests.
14017  ori_ab = orient3d(pc, pd, dummypoint, pb);
14018  ori_ca = orient3d(pd, pc, dummypoint, pa);
14019  if (ori_ab <= 0) {
14020  flipshpush(&(flipshs[0]));
14021  } else if (ori_ca <= 0) {
14022  flipshpush(&(flipshs[1]));
14023  }
14024  // Set 'searchsh' s.t. its origin is 'startpt'.
14025  *searchsh = flipshs[0];
14026  }
14027 
14028  return sscoutsegment(searchsh, endpt, insertsegflag, reporterrorflag,
14029  chkencflag);
14030 }
14031 
14033 // //
14034 // scarveholes() Remove triangles not in the facet. //
14035 // //
14036 // This routine re-uses the two global arrays: caveshlist and caveshbdlist. //
14037 // //
14039 
14040 void tetgenmesh::scarveholes(int holes, REAL* holelist)
14041 {
14042  face *parysh, searchsh, neighsh;
14043  enum locateresult loc;
14044  int i, j;
14045 
14046  // Get all triangles. Infect unprotected convex hull triangles.
14047  smarktest(recentsh);
14048  caveshlist->newindex((void **) &parysh);
14049  *parysh = recentsh;
14050  for (i = 0; i < caveshlist->objects; i++) {
14051  parysh = (face *) fastlookup(caveshlist, i);
14052  searchsh = *parysh;
14053  searchsh.shver = 0;
14054  for (j = 0; j < 3; j++) {
14055  spivot(searchsh, neighsh);
14056  // Is this side on the convex hull?
14057  if (neighsh.sh != NULL) {
14058  if (!smarktested(neighsh)) {
14059  smarktest(neighsh);
14060  caveshlist->newindex((void **) &parysh);
14061  *parysh = neighsh;
14062  }
14063  } else {
14064  // A hull side. Check if it is protected by a segment.
14065  if (!isshsubseg(searchsh)) {
14066  // Not protected. Save this face.
14067  if (!sinfected(searchsh)) {
14068  sinfect(searchsh);
14069  caveshbdlist->newindex((void **) &parysh);
14070  *parysh = searchsh;
14071  }
14072  }
14073  }
14074  senextself(searchsh);
14075  }
14076  }
14077 
14078  // Infect the triangles in the holes.
14079  for (i = 0; i < 3 * holes; i += 3) {
14080  searchsh = recentsh;
14081  loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
14082  if (loc != OUTSIDE) {
14083  sinfect(searchsh);
14084  caveshbdlist->newindex((void **) &parysh);
14085  *parysh = searchsh;
14086  }
14087  }
14088 
14089  // Find and infect all exterior triangles.
14090  for (i = 0; i < caveshbdlist->objects; i++) {
14091  parysh = (face *) fastlookup(caveshbdlist, i);
14092  searchsh = *parysh;
14093  searchsh.shver = 0;
14094  for (j = 0; j < 3; j++) {
14095  spivot(searchsh, neighsh);
14096  if (neighsh.sh != NULL) {
14097  if (!isshsubseg(searchsh)) {
14098  if (!sinfected(neighsh)) {
14099  sinfect(neighsh);
14100  caveshbdlist->newindex((void **) &parysh);
14101  *parysh = neighsh;
14102  }
14103  } else {
14104  sdissolve(neighsh); // Disconnect a protected face.
14105  }
14106  }
14107  senextself(searchsh);
14108  }
14109  }
14110 
14111  // Delete exterior triangles, unmark interior triangles.
14112  for (i = 0; i < caveshlist->objects; i++) {
14113  parysh = (face *) fastlookup(caveshlist, i);
14114  if (sinfected(*parysh)) {
14115  shellfacedealloc(subfaces, parysh->sh);
14116  } else {
14117  sunmarktest(*parysh);
14118  }
14119  }
14120 
14121  caveshlist->restart();
14122  caveshbdlist->restart();
14123 }
14124 
14126 // //
14127 // triangulate() Create a CDT for the facet. //
14128 // //
14129 // All vertices of the triangulation have type FACETVERTEX. The actual type //
14130 // of boundary vertices are set by the routine unifysements(). //
14131 // //
14132 // All segments created here will have a default marker '-1'. Some of these //
14133 // segments will get their actual marker defined in 'edgemarkerlist'. //
14134 // //
14136 
14137 int tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
14138  int holes, REAL* holelist)
14139 {
14140  face searchsh, newsh, *parysh;
14141  face newseg, *paryseg;
14142  point pa, pb, pc, *ppt, *cons;
14143  int iloc;
14144  int i, j;
14145 
14146  if (b->verbose > 2) {
14147  printf(" f%d: %ld vertices, %ld segments", shmark, ptlist->objects,
14148  conlist->objects);
14149  if (holes > 0) {
14150  printf(", %d holes", holes);
14151  }
14152  printf(".\n");
14153  }
14154 
14155  if (ptlist->objects < 2l) {
14156  // Not a segment or a facet.
14157  return 1;
14158  } else if (ptlist->objects == 2l) {
14159  pa = * (point *) fastlookup(ptlist, 0);
14160  pb = * (point *) fastlookup(ptlist, 1);
14161  if (distance(pa, pb) > 0) {
14162  // It is a single segment.
14163  makeshellface(subsegs, &newseg);
14164  setshvertices(newseg, pa, pb, NULL);
14165  setshellmark(newseg, -1);
14166  }
14167  if (pointtype(pa) == VOLVERTEX) {
14168  setpointtype(pa, FACETVERTEX);
14169  }
14170  if (pointtype(pb) == VOLVERTEX) {
14171  setpointtype(pb, FACETVERTEX);
14172  }
14173  return 1;
14174  } else if (ptlist->objects == 3) {
14175  pa = * (point *) fastlookup(ptlist, 0);
14176  pb = * (point *) fastlookup(ptlist, 1);
14177  pc = * (point *) fastlookup(ptlist, 2);
14178  } else {
14179  // Calculate an above point of this facet.
14180  if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
14181  if (!b->quiet) {
14182  printf("Warning: Unable to triangulate facet #%d. Skipped!\n",shmark);
14183  }
14184  return 0; // The point set is degenerate.
14185  }
14186  }
14187 
14188  // Create an initial triangulation.
14189  makeshellface(subfaces, &newsh);
14190  setshvertices(newsh, pa, pb, pc);
14191  setshellmark(newsh, shmark);
14192  recentsh = newsh;
14193 
14194  if (pointtype(pa) == VOLVERTEX) {
14195  setpointtype(pa, FACETVERTEX);
14196  }
14197  if (pointtype(pb) == VOLVERTEX) {
14198  setpointtype(pb, FACETVERTEX);
14199  }
14200  if (pointtype(pc) == VOLVERTEX) {
14201  setpointtype(pc, FACETVERTEX);
14202  }
14203 
14204  // Are there area constraints?
14205  if (b->quality && (in->facetconstraintlist != NULL)) {
14206  for (i = 0; i < in->numberoffacetconstraints; i++) {
14207  if (shmark == ((int) in->facetconstraintlist[i * 2])) {
14208  REAL area = in->facetconstraintlist[i * 2 + 1];
14209  setareabound(newsh, area);
14210  break;
14211  }
14212  }
14213  }
14214 
14215  if (ptlist->objects == 3) {
14216  // The triangulation only has one element.
14217  for (i = 0; i < 3; i++) {
14218  makeshellface(subsegs, &newseg);
14219  setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
14220  setshellmark(newseg, -1);
14221  ssbond(newsh, newseg);
14222  senextself(newsh);
14223  }
14224  return 1;
14225  }
14226 
14227  // Triangulate the facet. It may not success (due to rounding error, or
14228  // incorrect input data), use 'caveencshlist' and 'caveencseglist' are
14229  // re-used to store all the newly created subfaces and segments. So we
14230  // can clean them if the triangulation is not successful.
14231  caveencshlist->newindex((void **) &parysh);
14232  *parysh = newsh;
14233 
14234  // Incrementally build the triangulation.
14235  pinfect(pa);
14236  pinfect(pb);
14237  pinfect(pc);
14238  for (i = 0; i < ptlist->objects; i++) {
14239  ppt = (point *) fastlookup(ptlist, i);
14240  if (!pinfected(*ppt)) {
14241  searchsh = recentsh; // Start from 'recentsh'.
14242  iloc = (int) OUTSIDE;
14243  // Insert the vertex. Use Bowyer-Watson algo. Round the location.
14244  iloc = sinsertvertex(*ppt, &searchsh, NULL, iloc, 1, 1);
14245  if (iloc != ((int) ONVERTEX)) {
14246  // Point inserted successfully.
14247  if (pointtype(*ppt) == VOLVERTEX) {
14248  setpointtype(*ppt, FACETVERTEX);
14249  }
14250  // Save the set of new subfaces.
14251  for (j = 0; j < caveshbdlist->objects; j++) {
14252  // Get an old subface at edge [a, b].
14253  parysh = (face *) fastlookup(caveshbdlist, j);
14254  spivot(*parysh, searchsh); // The new subface [a, b, p].
14255  // Do not save a deleted new face (degenerated).
14256  if (searchsh.sh[3] != NULL) {
14257  caveencshlist->newindex((void **) &parysh);
14258  *parysh = searchsh;
14259  }
14260  }
14261  // Delete all removed subfaces.
14262  for (j = 0; j < caveshlist->objects; j++) {
14263  parysh = (face *) fastlookup(caveshlist, j);
14264  shellfacedealloc(subfaces, parysh->sh);
14265  }
14266  // Clear the global lists.
14267  caveshbdlist->restart();
14268  caveshlist->restart();
14269  cavesegshlist->restart();
14270  } else {
14271  // The facet triangulation is failed.
14272  break;
14273  }
14274  }
14275  } // i
14276  puninfect(pa);
14277  puninfect(pb);
14278  puninfect(pc);
14279 
14280  if (i < ptlist->objects) {
14281  //The facet triangulation is failed. Clean the new subfaces.
14282  // There is no new segment be created yet.
14283  if (!b->quiet) {
14284  printf("Warning: Fail to triangulate facet #%d. Skipped!\n", shmark);
14285  }
14286  for (i = 0; i < caveencshlist->objects; i++) {
14287  parysh = (face *) fastlookup(caveencshlist, i);
14288  if (parysh->sh[3] != NULL) {
14289  shellfacedealloc(subfaces, parysh->sh);
14290  }
14291  }
14292  caveencshlist->restart();
14293  return 0;
14294  }
14295 
14296  // Insert the segments.
14297  for (i = 0; i < conlist->objects; i++) {
14298  cons = (point *) fastlookup(conlist, i);
14299  searchsh = recentsh;
14300  iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
14301  if (iloc != (int) ONVERTEX) {
14302  // Not found due to roundoff errors. Do a brute-force search.
14303  subfaces->traversalinit();
14304  searchsh.sh = shellfacetraverse(subfaces);
14305  while (searchsh.sh != NULL) {
14306  // Only search the subface in the same facet.
14307  if (shellmark(searchsh) == shmark) {
14308  if ((point) searchsh.sh[3] == cons[0]) {
14309  searchsh.shver = 0; break;
14310  } else if ((point) searchsh.sh[4] == cons[0]) {
14311  searchsh.shver = 2; break;
14312  } else if ((point) searchsh.sh[5] == cons[0]) {
14313  searchsh.shver = 4; break;
14314  }
14315  }
14316  searchsh.sh = shellfacetraverse(subfaces);
14317  }
14318  }
14319  // Recover the segment. Some edges may be flipped.
14320  if (sscoutsegment(&searchsh, cons[1], 1, 1, 0) != SHAREEDGE) {
14321  break; // Fail to recover a segment.
14322  }
14323  // Save this newseg.
14324  sspivot(searchsh, newseg);
14325  caveencseglist->newindex((void **) &paryseg);
14326  *paryseg = newseg;
14327  if (flipstack != NULL) {
14328  // Recover locally Delaunay edges.
14329  lawsonflip();
14330  }
14331  } // i
14332 
14333  if (i < conlist->objects) {
14334  if (!b->quiet) {
14335  printf("Warning: Fail to recover a segment in facet #%d. Skipped!\n",
14336  shmark);
14337  }
14338  for (i = 0; i < caveencshlist->objects; i++) {
14339  parysh = (face *) fastlookup(caveencshlist, i);
14340  if (parysh->sh[3] != NULL) {
14341  shellfacedealloc(subfaces, parysh->sh);
14342  }
14343  }
14344  for (i = 0; i < caveencseglist->objects; i++) {
14345  paryseg = (face *) fastlookup(caveencseglist, i);
14346  if (paryseg->sh[3] != NULL) {
14347  shellfacedealloc(subsegs, paryseg->sh);
14348  }
14349  }
14350  caveencshlist->restart();
14351  caveencseglist->restart();
14352  return 0;
14353  }
14354 
14355  // Remove exterior and hole triangles.
14356  scarveholes(holes, holelist);
14357 
14358  caveencshlist->restart();
14359  caveencseglist->restart();
14360  return 1;
14361 }
14362 
14364 // //
14365 // unifysegments() Remove redundant segments and create face links. //
14366 // //
14367 // After this routine, although segments are unique, but some of them may be //
14368 // removed later by mergefacet(). All vertices still have type FACETVERTEX. //
14369 // //
14371 
14372 void tetgenmesh::unifysegments()
14373 {
14374  badface *facelink = NULL, *newlinkitem, *f1, *f2;
14375  face *facperverlist, sface;
14376  face subsegloop, testseg;
14377  point torg, tdest;
14378  REAL ori1, ori2, ori3;
14379  REAL n1[3], n2[3];
14380  REAL cosang, ang, ang_tol;
14381  int *idx2faclist;
14382  int idx, k, m;
14383 
14384  if (b->verbose > 1) {
14385  printf(" Unifying segments.\n");
14386  }
14387  // The limit dihedral angle that two facets are not overlapping.
14388  ang_tol = b->facet_overlap_ang_tol / 180.0 * PI;
14389  if (ang_tol < 0.0) ang_tol = 0.0;
14390 
14391  // Create a mapping from vertices to subfaces.
14392  makepoint2submap(subfaces, idx2faclist, facperverlist);
14393 
14394 
14395  subsegloop.shver = 0;
14396  subsegs->traversalinit();
14397  subsegloop.sh = shellfacetraverse(subsegs);
14398  while (subsegloop.sh != (shellface *) NULL) {
14399  torg = sorg(subsegloop);
14400  tdest = sdest(subsegloop);
14401 
14402  idx = pointmark(torg) - in->firstnumber;
14403  // Loop through the set of subfaces containing 'torg'. Get all the
14404  // subfaces containing the edge (torg, tdest). Save and order them
14405  // in 'sfacelist', the ordering is defined by the right-hand rule
14406  // with thumb points from torg to tdest.
14407  for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
14408  sface = facperverlist[k];
14409  // The face may be deleted if it is a duplicated face.
14410  if (sface.sh[3] == NULL) continue;
14411  // Search the edge torg->tdest.
14412  if (sdest(sface) != tdest) {
14413  senext2self(sface);
14414  sesymself(sface);
14415  }
14416  if (sdest(sface) != tdest) continue;
14417 
14418  // Save the face f in facelink.
14419  if (flippool->items >= 2) {
14420  f1 = facelink;
14421  for (m = 0; m < flippool->items - 1; m++) {
14422  f2 = f1->nextitem;
14423  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
14424  ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
14425  if (ori1 > 0) {
14426  // apex(f2) is below f1.
14427  if (ori2 > 0) {
14428  // apex(f) is below f1 (see Fig.1).
14429  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14430  if (ori3 > 0) {
14431  // apex(f) is below f2, insert it.
14432  break;
14433  } else if (ori3 < 0) {
14434  // apex(f) is above f2, continue.
14435  } else { // ori3 == 0;
14436  // f is coplanar and codirection with f2.
14437  report_overlapping_facets(&(f2->ss), &sface);
14438  break;
14439  }
14440  } else if (ori2 < 0) {
14441  // apex(f) is above f1 below f2, inset it (see Fig. 2).
14442  break;
14443  } else { // ori2 == 0;
14444  // apex(f) is coplanar with f1 (see Fig. 5).
14445  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14446  if (ori3 > 0) {
14447  // apex(f) is below f2, insert it.
14448  break;
14449  } else {
14450  // f is coplanar and codirection with f1.
14451  report_overlapping_facets(&(f1->ss), &sface);
14452  break;
14453  }
14454  }
14455  } else if (ori1 < 0) {
14456  // apex(f2) is above f1.
14457  if (ori2 > 0) {
14458  // apex(f) is below f1, continue (see Fig. 3).
14459  } else if (ori2 < 0) {
14460  // apex(f) is above f1 (see Fig.4).
14461  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14462  if (ori3 > 0) {
14463  // apex(f) is below f2, insert it.
14464  break;
14465  } else if (ori3 < 0) {
14466  // apex(f) is above f2, continue.
14467  } else { // ori3 == 0;
14468  // f is coplanar and codirection with f2.
14469  report_overlapping_facets(&(f2->ss), &sface);
14470  break;
14471  }
14472  } else { // ori2 == 0;
14473  // f is coplanar and with f1 (see Fig. 6).
14474  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14475  if (ori3 > 0) {
14476  // f is also codirection with f1.
14477  report_overlapping_facets(&(f1->ss), &sface);
14478  break;
14479  } else {
14480  // f is above f2, continue.
14481  }
14482  }
14483  } else { // ori1 == 0;
14484  // apex(f2) is coplanar with f1. By assumption, f1 is not
14485  // coplanar and codirection with f2.
14486  if (ori2 > 0) {
14487  // apex(f) is below f1, continue (see Fig. 7).
14488  } else if (ori2 < 0) {
14489  // apex(f) is above f1, insert it (see Fig. 7).
14490  break;
14491  } else { // ori2 == 0.
14492  // apex(f) is coplanar with f1 (see Fig. 8).
14493  // f is either codirection with f1 or is codirection with f2.
14494  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
14495  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
14496  if (dot(n1, n2) > 0) {
14497  report_overlapping_facets(&(f1->ss), &sface);
14498  } else {
14499  report_overlapping_facets(&(f2->ss), &sface);
14500  }
14501  break;
14502  }
14503  }
14504  // Go to the next item;
14505  f1 = f2;
14506  } // for (m = 0; ...)
14507  if (sface.sh[3] != NULL) {
14508  // Insert sface between f1 and f2.
14509  newlinkitem = (badface *) flippool->alloc();
14510  newlinkitem->ss = sface;
14511  newlinkitem->nextitem = f1->nextitem;
14512  f1->nextitem = newlinkitem;
14513  }
14514  } else if (flippool->items == 1) {
14515  f1 = facelink;
14516  // Make sure that f is not coplanar and codirection with f1.
14517  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
14518  if (ori1 == 0) {
14519  // f is coplanar with f1 (see Fig. 8).
14520  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
14521  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
14522  if (dot(n1, n2) > 0) {
14523  // The two faces are codirectional as well.
14524  report_overlapping_facets(&(f1->ss), &sface);
14525  }
14526  }
14527  // Add this face to link if it is not deleted.
14528  if (sface.sh[3] != NULL) {
14529  // Add this face into link.
14530  newlinkitem = (badface *) flippool->alloc();
14531  newlinkitem->ss = sface;
14532  newlinkitem->nextitem = NULL;
14533  f1->nextitem = newlinkitem;
14534  }
14535  } else {
14536  // The first face.
14537  newlinkitem = (badface *) flippool->alloc();
14538  newlinkitem->ss = sface;
14539  newlinkitem->nextitem = NULL;
14540  facelink = newlinkitem;
14541  }
14542  } // for (k = idx2faclist[idx]; ...)
14543 
14544 
14545  // Set the connection between this segment and faces containing it,
14546  // at the same time, remove redundant segments.
14547  f1 = facelink;
14548  for (k = 0; k < flippool->items; k++) {
14549  sspivot(f1->ss, testseg);
14550  // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
14551  if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
14552  shellfacedealloc(subsegs, testseg.sh);
14553  }
14554  // Bonds the subface and the segment together.
14555  ssbond(f1->ss, subsegloop);
14556  f1 = f1->nextitem;
14557  }
14558 
14559  // Create the face ring at the segment.
14560  if (flippool->items > 1) {
14561  f1 = facelink;
14562  for (k = 1; k <= flippool->items; k++) {
14563  k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
14564  // Calculate the dihedral angle between the two facet.
14565  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
14566  facenormal(torg, tdest, sapex(f2->ss), n2, 1, NULL);
14567  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
14568  // Rounding.
14569  if (cosang > 1.0) cosang = 1.0;
14570  else if (cosang < -1.0) cosang = -1.0;
14571  ang = acos(cosang);
14572  if (ang < ang_tol) {
14573  // Two facets are treated as overlapping each other.
14574  report_overlapping_facets(&(f1->ss), &(f2->ss), ang);
14575  } else {
14576  // Record the smallest input dihedral angle.
14577  if (ang < minfacetdihed) {
14578  minfacetdihed = ang;
14579  }
14580  sbond1(f1->ss, f2->ss);
14581  }
14582  f1 = f2;
14583  }
14584  }
14585 
14586  flippool->restart();
14587 
14588  // Are there length constraints?
14589  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
14590  int e1, e2;
14591  REAL len;
14592  for (k = 0; k < in->numberofsegmentconstraints; k++) {
14593  e1 = (int) in->segmentconstraintlist[k * 3];
14594  e2 = (int) in->segmentconstraintlist[k * 3 + 1];
14595  if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
14596  ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
14597  len = in->segmentconstraintlist[k * 3 + 2];
14598  setareabound(subsegloop, len);
14599  break;
14600  }
14601  }
14602  }
14603 
14604  subsegloop.sh = shellfacetraverse(subsegs);
14605  }
14606 
14607  delete [] idx2faclist;
14608  delete [] facperverlist;
14609 }
14610 
14612 // //
14613 // identifyinputedges() Identify input edges. //
14614 // //
14615 // A set of input edges is provided in the 'in->edgelist'. We find these //
14616 // edges in the surface mesh and make them segments of the mesh. //
14617 // //
14618 // It is possible that an input edge is not in any facet, i.e.,it is a float-//
14619 // segment inside the volume. //
14620 // //
14622 
14623 void tetgenmesh::identifyinputedges(point *idx2verlist)
14624 {
14625  face* shperverlist;
14626  int* idx2shlist;
14627  face searchsh, neighsh;
14628  face segloop, checkseg, newseg;
14629  point checkpt, pa = NULL, pb = NULL;
14630  int *endpts;
14631  int edgemarker;
14632  int idx, i, j;
14633 
14634  int e1, e2;
14635  REAL len;
14636 
14637  if (!b->quiet) {
14638  printf("Inserting edges ...\n");
14639  }
14640 
14641  // Construct a map from points to subfaces.
14642  makepoint2submap(subfaces, idx2shlist, shperverlist);
14643 
14644  // Process the set of input edges.
14645  for (i = 0; i < in->numberofedges; i++) {
14646  endpts = &(in->edgelist[(i << 1)]);
14647  if (endpts[0] == endpts[1]) {
14648  if (!b->quiet) {
14649  printf("Warning: Edge #%d is degenerated. Skipped.\n", i);
14650  }
14651  continue; // Skip a degenerated edge.
14652  }
14653  // Recall that all existing segments have a default marker '-1'.
14654  // We assign all identified segments a default marker '-2'.
14655  edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : -2;
14656 
14657  // Find a face contains the edge.
14658  newseg.sh = NULL;
14659  searchsh.sh = NULL;
14660  idx = endpts[0] - in->firstnumber;
14661  for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
14662  checkpt = sdest(shperverlist[j]);
14663  if (pointmark(checkpt) == endpts[1]) {
14664  searchsh = shperverlist[j];
14665  break; // Found.
14666  } else {
14667  checkpt = sapex(shperverlist[j]);
14668  if (pointmark(checkpt) == endpts[1]) {
14669  senext2(shperverlist[j], searchsh);
14670  sesymself(searchsh);
14671  break;
14672  }
14673  }
14674  } // j
14675 
14676  if (searchsh.sh != NULL) {
14677  // Check if this edge is already a segment of the mesh.
14678  sspivot(searchsh, checkseg);
14679  if (checkseg.sh != NULL) {
14680  // This segment already exist.
14681  newseg = checkseg;
14682  } else {
14683  // Create a new segment at this edge.
14684  pa = sorg(searchsh);
14685  pb = sdest(searchsh);
14686  makeshellface(subsegs, &newseg);
14687  setshvertices(newseg, pa, pb, NULL);
14688  ssbond(searchsh, newseg);
14689  spivot(searchsh, neighsh);
14690  if (neighsh.sh != NULL) {
14691  ssbond(neighsh, newseg);
14692  }
14693  }
14694  } else {
14695  // It is a dangling segment (not belong to any facets).
14696  // Get the two endpoints of this segment.
14697  pa = idx2verlist[endpts[0]];
14698  pb = idx2verlist[endpts[1]];
14699  if (pa == pb) {
14700  if (!b->quiet) {
14701  printf("Warning: Edge #%d is degenerated. Skipped.\n", i);
14702  }
14703  continue;
14704  }
14705  // Check if segment [a,b] already exists.
14706  // TODO: Change the brute-force search. Slow!
14707  point *ppt;
14708  subsegs->traversalinit();
14709  segloop.sh = shellfacetraverse(subsegs);
14710  while (segloop.sh != NULL) {
14711  ppt = (point *) &(segloop.sh[3]);
14712  if (((ppt[0] == pa) && (ppt[1] == pb)) ||
14713  ((ppt[0] == pb) && (ppt[1] == pa))) {
14714  // Found!
14715  newseg = segloop;
14716  break;
14717  }
14718  segloop.sh = shellfacetraverse(subsegs);
14719  }
14720  if (newseg.sh == NULL) {
14721  makeshellface(subsegs, &newseg);
14722  setshvertices(newseg, pa, pb, NULL);
14723  }
14724  }
14725 
14726  setshellmark(newseg, edgemarker);
14727 
14728  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
14729  for (i = 0; i < in->numberofsegmentconstraints; i++) {
14730  e1 = (int) in->segmentconstraintlist[i * 3];
14731  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
14732  if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
14733  ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
14734  len = in->segmentconstraintlist[i * 3 + 2];
14735  setareabound(newseg, len);
14736  break;
14737  }
14738  }
14739  }
14740  } // i
14741 
14742  delete [] shperverlist;
14743  delete [] idx2shlist;
14744 }
14745 
14747 // //
14748 // mergefacets() Merge adjacent facets. //
14749 // //
14751 
14752 void tetgenmesh::mergefacets()
14753 {
14754  face parentsh, neighsh, neineish;
14755  face segloop;
14756  point pa, pb, pc, pd;
14757  REAL n1[3], n2[3];
14758  REAL cosang, cosang_tol;
14759 
14760 
14761  // Allocate an array to save calcaulated dihedral angles at segments.
14762  arraypool *dihedangarray = new arraypool(sizeof(double), 10);
14763  REAL *paryang = NULL;
14764 
14765  // First, remove coplanar segments.
14766  // The dihedral angle bound for two different facets.
14767  cosang_tol = cos(b->facet_separate_ang_tol / 180.0 * PI);
14768 
14769  subsegs->traversalinit();
14770  segloop.sh = shellfacetraverse(subsegs);
14771  while (segloop.sh != (shellface *) NULL) {
14772  // Only remove a segment if it has a marker '-1'.
14773  if (shellmark(segloop) != -1) {
14774  segloop.sh = shellfacetraverse(subsegs);
14775  continue;
14776  }
14777  spivot(segloop, parentsh);
14778  if (parentsh.sh != NULL) {
14779  spivot(parentsh, neighsh);
14780  if (neighsh.sh != NULL) {
14781  spivot(neighsh, neineish);
14782  if (neineish.sh == parentsh.sh) {
14783  // Exactly two subfaces at this segment.
14784  // Only merge them if they have the same boundary marker.
14785  if (shellmark(parentsh) == shellmark(neighsh)) {
14786  pa = sorg(segloop);
14787  pb = sdest(segloop);
14788  pc = sapex(parentsh);
14789  pd = sapex(neighsh);
14790  // Calculate the dihedral angle at the segment [a,b].
14791  facenormal(pa, pb, pc, n1, 1, NULL);
14792  facenormal(pa, pb, pd, n2, 1, NULL);
14793  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
14794  if (cosang < cosang_tol) {
14795  ssdissolve(parentsh);
14796  ssdissolve(neighsh);
14797  shellfacedealloc(subsegs, segloop.sh);
14798  // Add the edge to flip stack.
14799  flipshpush(&parentsh);
14800  } else {
14801  // Save 'cosang' to avoid re-calculate it.
14802  // Re-use the pointer at the first segment.
14803  dihedangarray->newindex((void **) &paryang);
14804  *paryang = cosang;
14805  segloop.sh[6] = (shellface) paryang;
14806  }
14807  }
14808  } // if (neineish.sh == parentsh.sh)
14809  }
14810  }
14811  segloop.sh = shellfacetraverse(subsegs);
14812  }
14813 
14814  // Second, remove ridge segments at small angles.
14815  // The dihedral angle bound for two different facets.
14816  cosang_tol = cos(b->facet_small_ang_tol / 180.0 * PI);
14817  REAL cosang_sep_tol = cos((b->facet_separate_ang_tol - 5.0) / 180.0 * PI);
14818  face shloop;
14819  face seg1, seg2;
14820  REAL cosang1, cosang2;
14821  int i, j;
14822 
14823  subfaces->traversalinit();
14824  shloop.sh = shellfacetraverse(subfaces);
14825  while (shloop.sh != (shellface *) NULL) {
14826  for (i = 0; i < 3; i++) {
14827  if (isshsubseg(shloop)) {
14828  senext(shloop, neighsh);
14829  if (isshsubseg(neighsh)) {
14830  // Found two segments sharing at one vertex.
14831  // Check if they form a small angle.
14832  pa = sorg(shloop);
14833  pb = sdest(shloop);
14834  pc = sapex(shloop);
14835  for (j = 0; j < 3; j++) n1[j] = pa[j] - pb[j];
14836  for (j = 0; j < 3; j++) n2[j] = pc[j] - pb[j];
14837  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
14838  if (cosang > cosang_tol) {
14839  // Found a small angle.
14840  segloop.sh = NULL;
14841  sspivot(shloop, seg1);
14842  sspivot(neighsh, seg2);
14843  if (seg1.sh[6] != NULL) {
14844  paryang = (REAL *) (seg1.sh[6]);
14845  cosang1 = *paryang;
14846  } else {
14847  cosang1 = 1.0; // 0 degree;
14848  }
14849  if (seg2.sh[6] != NULL) {
14850  paryang = (REAL *) (seg2.sh[6]);
14851  cosang2 = *paryang;
14852  } else {
14853  cosang2 = 1.0; // 0 degree;
14854  }
14855  if (cosang1 < cosang_sep_tol) {
14856  if (cosang2 < cosang_sep_tol) {
14857  if (cosang1 < cosang2) {
14858  segloop = seg1;
14859  } else {
14860  segloop = seg2;
14861  }
14862  } else {
14863  segloop = seg1;
14864  }
14865  } else {
14866  if (cosang2 < cosang_sep_tol) {
14867  segloop = seg2;
14868  }
14869  }
14870  if (segloop.sh != NULL) {
14871  // Remove this segment.
14872  segloop.shver = 0;
14873  spivot(segloop, parentsh);
14874  spivot(parentsh, neighsh);
14875  ssdissolve(parentsh);
14876  ssdissolve(neighsh);
14877  shellfacedealloc(subsegs, segloop.sh);
14878  // Add the edge to flip stack.
14879  flipshpush(&parentsh);
14880  break;
14881  }
14882  }
14883  } // if (isshsubseg)
14884  } // if (isshsubseg)
14885  senextself(shloop);
14886  }
14887  shloop.sh = shellfacetraverse(subfaces);
14888  }
14889 
14890  delete dihedangarray;
14891 
14892  if (flipstack != NULL) {
14893  lawsonflip(); // Recover Delaunayness.
14894  }
14895 }
14896 
14898 // //
14899 // meshsurface() Create a surface mesh of the input PLC. //
14900 // //
14902 
14903 void tetgenmesh::meshsurface()
14904 {
14905  arraypool *ptlist, *conlist;
14906  point *idx2verlist;
14907  point tstart, tend, *pnewpt, *cons;
14908  tetgenio::facet *f;
14909  tetgenio::polygon *p;
14910  int end1, end2;
14911  int shmark, i, j;
14912 
14913  if (!b->quiet) {
14914  printf("Creating surface mesh ...\n");
14915  }
14916 
14917  // Create a map from indices to points.
14918  makeindex2pointmap(idx2verlist);
14919 
14920  // Initialize arrays (block size: 2^8 = 256).
14921  ptlist = new arraypool(sizeof(point *), 8);
14922  conlist = new arraypool(2 * sizeof(point *), 8);
14923 
14924  // Loop the facet list, triangulate each facet.
14925  for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
14926 
14927  // Get a facet F.
14928  f = &in->facetlist[shmark - 1];
14929 
14930  // Process the duplicated points first, they are marked with type
14931  // DUPLICATEDVERTEX. If p and q are duplicated, and p'index > q's,
14932  // then p is substituted by q.
14933  if (dupverts > 0l) {
14934  // Loop all polygons of this facet.
14935  for (i = 0; i < f->numberofpolygons; i++) {
14936  p = &(f->polygonlist[i]);
14937  // Loop other vertices of this polygon.
14938  for (j = 0; j < p->numberofvertices; j++) {
14939  end1 = p->vertexlist[j];
14940  tstart = idx2verlist[end1];
14941  if (pointtype(tstart) == DUPLICATEDVERTEX) {
14942  // Reset the index of vertex-j.
14943  tend = point2ppt(tstart);
14944  end2 = pointmark(tend);
14945  p->vertexlist[j] = end2;
14946  }
14947  }
14948  }
14949  }
14950 
14951  // Loop polygons of F, get the set of vertices and segments.
14952  for (i = 0; i < f->numberofpolygons; i++) {
14953  // Get a polygon.
14954  p = &(f->polygonlist[i]);
14955  // Get the first vertex.
14956  end1 = p->vertexlist[0];
14957  if ((end1 < in->firstnumber) ||
14958  (end1 >= in->firstnumber + in->numberofpoints)) {
14959  if (!b->quiet) {
14960  printf("Warning: Invalid the 1st vertex %d of polygon", end1);
14961  printf(" %d in facet %d.\n", i + 1, shmark);
14962  }
14963  continue; // Skip this polygon.
14964  }
14965  tstart = idx2verlist[end1];
14966  // Add tstart to V if it haven't been added yet.
14967  if (!pinfected(tstart)) {
14968  pinfect(tstart);
14969  ptlist->newindex((void **) &pnewpt);
14970  *pnewpt = tstart;
14971  }
14972  // Loop other vertices of this polygon.
14973  for (j = 1; j <= p->numberofvertices; j++) {
14974  // get a vertex.
14975  if (j < p->numberofvertices) {
14976  end2 = p->vertexlist[j];
14977  } else {
14978  end2 = p->vertexlist[0]; // Form a loop from last to first.
14979  }
14980  if ((end2 < in->firstnumber) ||
14981  (end2 >= in->firstnumber + in->numberofpoints)) {
14982  if (!b->quiet) {
14983  printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1);
14984  printf(" in facet %d.\n", shmark);
14985  }
14986  } else {
14987  if (end1 != end2) {
14988  // 'end1' and 'end2' form a segment.
14989  tend = idx2verlist[end2];
14990  // Add tstart to V if it haven't been added yet.
14991  if (!pinfected(tend)) {
14992  pinfect(tend);
14993  ptlist->newindex((void **) &pnewpt);
14994  *pnewpt = tend;
14995  }
14996  // Save the segment in S (conlist).
14997  conlist->newindex((void **) &cons);
14998  cons[0] = tstart;
14999  cons[1] = tend;
15000  // Set the start for next continuous segment.
15001  end1 = end2;
15002  tstart = tend;
15003  } else {
15004  // Two identical vertices mean an isolated vertex of F.
15005  if (p->numberofvertices > 2) {
15006  // This may be an error in the input, anyway, we can continue
15007  // by simply skipping this segment.
15008  if (!b->quiet) {
15009  printf("Warning: Polygon %d has two identical verts", i + 1);
15010  printf(" in facet %d.\n", shmark);
15011  }
15012  }
15013  // Ignore this vertex.
15014  }
15015  }
15016  // Is the polygon degenerate (a segment or a vertex)?
15017  if (p->numberofvertices == 2) break;
15018  }
15019  }
15020  // Unmark vertices.
15021  for (i = 0; i < ptlist->objects; i++) {
15022  pnewpt = (point *) fastlookup(ptlist, i);
15023  puninfect(*pnewpt);
15024  }
15025 
15026  // Triangulate F into a CDT.
15027  // If in->facetmarklist is NULL, use the default marker -1.
15028  triangulate(in->facetmarkerlist ? in->facetmarkerlist[shmark - 1] : -1,
15029  ptlist, conlist, f->numberofholes, f->holelist);
15030 
15031  // Clear working lists.
15032  ptlist->restart();
15033  conlist->restart();
15034  }
15035 
15036  if (!b->diagnose) {
15037  // Remove redundant segments and build the face links.
15038  unifysegments();
15039  if (in->numberofedges > 0) {
15040  // There are input segments. Insert them.
15041  identifyinputedges(idx2verlist);
15042  }
15043  if (!b->psc && !b->nomergefacet &&
15044  (!b->nobisect || (b->nobisect && !b->nobisect_nomerge))) {
15045  // Merge coplanar facets.
15046  mergefacets();
15047  }
15048  }
15049 
15050  if (b->object == tetgenbehavior::STL) {
15051  // Remove redundant vertices (for .stl input mesh).
15052  jettisonnodes();
15053  }
15054 
15055  if (b->verbose) {
15056  printf(" %ld (%ld) subfaces (segments).\n", subfaces->items,
15057  subsegs->items);
15058  }
15059 
15060  // The total number of iunput segments.
15061  insegments = subsegs->items;
15062 
15063  delete [] idx2verlist;
15064  delete ptlist;
15065  delete conlist;
15066 }
15067 
15069 // //
15070 // interecursive() Recursively do intersection test on a set of triangles.//
15071 // //
15072 // Recursively split the set 'subfacearray' of subfaces into two sets using //
15073 // a cut plane parallel to x-, or, y-, or z-axis. The split criteria are //
15074 // follows. Assume the cut plane is H, and H+ denotes the left halfspace of //
15075 // H, and H- denotes the right halfspace of H; and s be a subface: //
15076 // //
15077 // (1) If all points of s lie at H+, put it into left array; //
15078 // (2) If all points of s lie at H-, put it into right array; //
15079 // (3) If some points of s lie at H+ and some of lie at H-, or some //
15080 // points lie on H, put it into both arraies. //
15081 // //
15082 // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis //
15083 // if axis == '2'. If current cut plane is parallel to the x-axis, the next //
15084 // one will be parallel to y-axis, and the next one after the next is z-axis,//
15085 // and then alternately return back to x-axis. //
15086 // //
15087 // Stop splitting when the number of triangles of the input array is not //
15088 // decreased anymore. Do tests on the current set. //
15089 // //
15091 
15092 void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
15093  int axis, REAL bxmin, REAL bxmax, REAL bymin,
15094  REAL bymax, REAL bzmin, REAL bzmax,
15095  int* internum)
15096 {
15097  shellface **leftarray, **rightarray;
15098  face sface1, sface2;
15099  point p1, p2, p3;
15100  point p4, p5, p6;
15101  enum interresult intersect;
15102  REAL split;
15103  bool toleft, toright;
15104  int leftsize, rightsize;
15105  int i, j;
15106 
15107  if (b->verbose > 2) {
15108  printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
15109  arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
15110  axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
15111  }
15112 
15113  leftarray = new shellface*[arraysize];
15114  if (leftarray == NULL) {
15115  terminatetetgen(this, 1);
15116  }
15117  rightarray = new shellface*[arraysize];
15118  if (rightarray == NULL) {
15119  terminatetetgen(this, 1);
15120  }
15121  leftsize = rightsize = 0;
15122 
15123  if (axis == 0) {
15124  // Split along x-axis.
15125  split = 0.5 * (bxmin + bxmax);
15126  } else if (axis == 1) {
15127  // Split along y-axis.
15128  split = 0.5 * (bymin + bymax);
15129  } else {
15130  // Split along z-axis.
15131  split = 0.5 * (bzmin + bzmax);
15132  }
15133 
15134  for (i = 0; i < arraysize; i++) {
15135  sface1.sh = subfacearray[i];
15136  p1 = (point) sface1.sh[3];
15137  p2 = (point) sface1.sh[4];
15138  p3 = (point) sface1.sh[5];
15139  toleft = toright = false;
15140  if (p1[axis] < split) {
15141  toleft = true;
15142  if (p2[axis] >= split || p3[axis] >= split) {
15143  toright = true;
15144  }
15145  } else if (p1[axis] > split) {
15146  toright = true;
15147  if (p2[axis] <= split || p3[axis] <= split) {
15148  toleft = true;
15149  }
15150  } else {
15151  // p1[axis] == split;
15152  toleft = true;
15153  toright = true;
15154  }
15155  if (toleft) {
15156  leftarray[leftsize] = sface1.sh;
15157  leftsize++;
15158  }
15159  if (toright) {
15160  rightarray[rightsize] = sface1.sh;
15161  rightsize++;
15162  }
15163  }
15164 
15165  if (leftsize < arraysize && rightsize < arraysize) {
15166  // Continue to partition the input set. Now 'subfacearray' has been
15167  // split into two sets, it's memory can be freed. 'leftarray' and
15168  // 'rightarray' will be freed in the next recursive (after they're
15169  // partitioned again or performing tests).
15170  delete [] subfacearray;
15171  // Continue to split these two sets.
15172  if (axis == 0) {
15173  interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
15174  bzmin, bzmax, internum);
15175  interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
15176  bzmin, bzmax, internum);
15177  } else if (axis == 1) {
15178  interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
15179  bzmin, bzmax, internum);
15180  interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
15181  bzmin, bzmax, internum);
15182  } else {
15183  interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
15184  bzmin, split, internum);
15185  interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
15186  split, bzmax, internum);
15187  }
15188  } else {
15189  if (b->verbose > 1) {
15190  printf(" Checking intersecting faces.\n");
15191  }
15192  // Perform a brute-force compare on the set.
15193  for (i = 0; i < arraysize; i++) {
15194  sface1.sh = subfacearray[i];
15195  p1 = (point) sface1.sh[3];
15196  p2 = (point) sface1.sh[4];
15197  p3 = (point) sface1.sh[5];
15198  for (j = i + 1; j < arraysize; j++) {
15199  sface2.sh = subfacearray[j];
15200  p4 = (point) sface2.sh[3];
15201  p5 = (point) sface2.sh[4];
15202  p6 = (point) sface2.sh[5];
15203  intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
15204  if (intersect == INTERSECT || intersect == SHAREFACE) {
15205  if (!b->quiet) {
15206  if (intersect == INTERSECT) {
15207  printf(" Facet #%d intersects facet #%d at triangles:\n",
15208  shellmark(sface1), shellmark(sface2));
15209  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
15210  pointmark(p1), pointmark(p2), pointmark(p3),
15211  pointmark(p4), pointmark(p5), pointmark(p6));
15212  } else {
15213  printf(" Facet #%d duplicates facet #%d at triangle:\n",
15214  shellmark(sface1), shellmark(sface2));
15215  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
15216  pointmark(p1), pointmark(p2), pointmark(p3),
15217  pointmark(p4), pointmark(p5), pointmark(p6));
15218  }
15219  }
15220  // Increase the number of intersecting pairs.
15221  (*internum)++;
15222  // Infect these two faces (although they may already be infected).
15223  sinfect(sface1);
15224  sinfect(sface2);
15225  }
15226  }
15227  }
15228  // Don't forget to free all three arrays. No further partition.
15229  delete [] leftarray;
15230  delete [] rightarray;
15231  delete [] subfacearray;
15232  }
15233 }
15234 
15236 // //
15237 // detectinterfaces() Detect intersecting triangles. //
15238 // //
15239 // Given a set of triangles, find the pairs of intersecting triangles from //
15240 // them. Here the set of triangles is in 'subfaces' which is a surface mesh //
15241 // of a PLC (.poly or .smesh). //
15242 // //
15243 // To detect whether two triangles are intersecting is done by the routine //
15244 // 'tri_tri_inter()'. The algorithm for the test is very simple and stable. //
15245 // It is based on geometric orientation test which uses exact arithmetics. //
15246 // //
15247 // Use divide-and-conquer algorithm for reducing the number of intersection //
15248 // tests. Start from the bounding box of the input point set, recursively //
15249 // partition the box into smaller boxes, until the number of triangles in a //
15250 // box is not decreased anymore. Then perform triangle-triangle tests on the //
15251 // remaining set of triangles. The memory allocated in the input set is //
15252 // freed immediately after it has been partitioned into two arrays. So it //
15253 // can be re-used for the consequent partitions. //
15254 // //
15255 // On return, the pool 'subfaces' will be cleared, and only the intersecting //
15256 // triangles remain for output (to a .face file). //
15257 // //
15259 
15260 void tetgenmesh::detectinterfaces()
15261 {
15262  shellface **subfacearray;
15263  face shloop;
15264  int internum;
15265  int i;
15266 
15267  if (!b->quiet) {
15268  printf("Detecting self-intersecting facets...\n");
15269  }
15270 
15271  // Construct a map from indices to subfaces;
15272  subfacearray = new shellface*[subfaces->items];
15273  subfaces->traversalinit();
15274  shloop.sh = shellfacetraverse(subfaces);
15275  i = 0;
15276  while (shloop.sh != (shellface *) NULL) {
15277  subfacearray[i] = shloop.sh;
15278  shloop.sh = shellfacetraverse(subfaces);
15279  i++;
15280  }
15281 
15282  internum = 0;
15283  // Recursively split the set of triangles into two sets using a cut plane
15284  // parallel to x-, or, y-, or z-axis. Stop splitting when the number
15285  // of subfaces is not decreasing anymore. Do tests on the current set.
15286  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
15287  zmin, zmax, &internum);
15288 
15289  if (!b->quiet) {
15290  if (internum > 0) {
15291  printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
15292  } else {
15293  printf("\nNo faces are intersecting.\n\n");
15294  }
15295  }
15296 
15297  if (internum > 0) {
15298  // Traverse all subfaces, deallocate those have not been infected (they
15299  // are not intersecting faces). Uninfect those have been infected.
15300  // After this loop, only intersecting faces remain.
15301  subfaces->traversalinit();
15302  shloop.sh = shellfacetraverse(subfaces);
15303  while (shloop.sh != (shellface *) NULL) {
15304  if (sinfected(shloop)) {
15305  suninfect(shloop);
15306  } else {
15307  shellfacedealloc(subfaces, shloop.sh);
15308  }
15309  shloop.sh = shellfacetraverse(subfaces);
15310  }
15311  } else {
15312  // Deallocate all subfaces.
15313  subfaces->restart();
15314  }
15315 }
15316 
15320 
15324 
15326 // //
15327 // makesegmentendpointsmap() Create a map from a segment to its endpoints.//
15328 // //
15329 // The map is saved in the array 'segmentendpointslist'. The length of this //
15330 // array is twice the number of segments. Each segment is assigned a unique //
15331 // index (starting from 0). //
15332 // //
15334 
15335 void tetgenmesh::makesegmentendpointsmap()
15336 {
15337  arraypool *segptlist;
15338  face segloop, prevseg, nextseg;
15339  point eorg, edest, *parypt;
15340  int segindex = 0, idx = 0;
15341  int i;
15342 
15343  if (b->verbose > 0) {
15344  printf(" Creating the segment-endpoints map.\n");
15345  }
15346 
15347  segptlist = new arraypool(2 * sizeof(point), 10);
15348 
15349  // A segment s may have been split into many subsegments. Operate the one
15350  // which contains the origin of s. Then mark the rest of subsegments.
15351  subsegs->traversalinit();
15352  segloop.sh = shellfacetraverse(subsegs);
15353  segloop.shver = 0;
15354  while (segloop.sh != NULL) {
15355  senext2(segloop, prevseg);
15356  spivotself(prevseg);
15357  if (prevseg.sh == NULL) {
15358  eorg = sorg(segloop);
15359  edest = sdest(segloop);
15360  setfacetindex(segloop, segindex);
15361  senext(segloop, nextseg);
15362  spivotself(nextseg);
15363  while (nextseg.sh != NULL) {
15364  setfacetindex(nextseg, segindex);
15365  nextseg.shver = 0;
15366  if (sorg(nextseg) != edest) sesymself(nextseg);
15367  edest = sdest(nextseg);
15368  // Go the next connected subsegment at edest.
15369  senextself(nextseg);
15370  spivotself(nextseg);
15371  }
15372  segptlist->newindex((void **) &parypt);
15373  parypt[0] = eorg;
15374  parypt[1] = edest;
15375  segindex++;
15376  }
15377  segloop.sh = shellfacetraverse(subsegs);
15378  }
15379 
15380  if (b->verbose) {
15381  printf(" Found %ld segments.\n", segptlist->objects);
15382  }
15383 
15384  segmentendpointslist = new point[segptlist->objects * 2];
15385 
15386  totalworkmemory += (segptlist->objects * 2) * sizeof(point *);
15387 
15388  for (i = 0; i < segptlist->objects; i++) {
15389  parypt = (point *) fastlookup(segptlist, i);
15390  segmentendpointslist[idx++] = parypt[0];
15391  segmentendpointslist[idx++] = parypt[1];
15392  }
15393 
15394  delete segptlist;
15395 }
15396 
15398 // //
15399 // finddirection() Find the tet on the path from one point to another. //
15400 // //
15401 // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
15402 // 'searchtet' contains a tet on the path, its origin does not change. //
15403 // //
15404 // The return value indicates one of the following cases (let 'searchtet' be //
15405 // abcd, a is the origin of the path): //
15406 // - ACROSSVERT, edge ab is collinear with the path; //
15407 // - ACROSSEDGE, edge bc intersects with the path; //
15408 // - ACROSSFACE, face bcd intersects with the path. //
15409 // //
15410 // WARNING: This routine is designed for convex triangulations, and will not //
15411 // generally work after the holes and concavities have been carved. //
15412 // //
15414 
15415 enum tetgenmesh::interresult
15416  tetgenmesh::finddirection(triface* searchtet, point endpt)
15417 {
15418  triface neightet;
15419  point pa, pb, pc, pd;
15420  enum {HMOVE, RMOVE, LMOVE} nextmove;
15421  REAL hori, rori, lori;
15422  int t1ver;
15423  int s;
15424 
15425  // The origin is fixed.
15426  pa = org(*searchtet);
15427  if ((point) searchtet->tet[7] == dummypoint) {
15428  // A hull tet. Choose the neighbor of its base face.
15429  decode(searchtet->tet[3], *searchtet);
15430  // Reset the origin to be pa.
15431  if ((point) searchtet->tet[4] == pa) {
15432  searchtet->ver = 11;
15433  } else if ((point) searchtet->tet[5] == pa) {
15434  searchtet->ver = 3;
15435  } else if ((point) searchtet->tet[6] == pa) {
15436  searchtet->ver = 7;
15437  } else {
15438  searchtet->ver = 0;
15439  }
15440  }
15441 
15442  pb = dest(*searchtet);
15443  // Check whether the destination or apex is 'endpt'.
15444  if (pb == endpt) {
15445  // pa->pb is the search edge.
15446  return ACROSSVERT;
15447  }
15448 
15449  pc = apex(*searchtet);
15450  if (pc == endpt) {
15451  // pa->pc is the search edge.
15452  eprevesymself(*searchtet);
15453  return ACROSSVERT;
15454  }
15455 
15456  // Walk through tets around pa until the right one is found.
15457  while (1) {
15458 
15459  pd = oppo(*searchtet);
15460  // Check whether the opposite vertex is 'endpt'.
15461  if (pd == endpt) {
15462  // pa->pd is the search edge.
15463  esymself(*searchtet);
15464  enextself(*searchtet);
15465  return ACROSSVERT;
15466  }
15467  // Check if we have entered outside of the domain.
15468  if (pd == dummypoint) {
15469  // This is possible when the mesh is non-convex.
15470  if (nonconvex) {
15471  return ACROSSFACE; // return ACROSSSUB; // Hit a bounday.
15472  } else {
15473  terminatetetgen(this, 2);
15474  }
15475  }
15476 
15477  // Now assume that the base face abc coincides with the horizon plane,
15478  // and d lies above the horizon. The search point 'endpt' may lie
15479  // above or below the horizon. We test the orientations of 'endpt'
15480  // with respect to three planes: abc (horizon), bad (right plane),
15481  // and acd (left plane).
15482  hori = orient3d(pa, pb, pc, endpt);
15483  rori = orient3d(pb, pa, pd, endpt);
15484  lori = orient3d(pa, pc, pd, endpt);
15485 
15486  // Now decide the tet to move. It is possible there are more than one
15487  // tets are viable moves. Is so, randomly choose one.
15488  if (hori > 0) {
15489  if (rori > 0) {
15490  if (lori > 0) {
15491  // Any of the three neighbors is a viable move.
15492  s = randomnation(3);
15493  if (s == 0) {
15494  nextmove = HMOVE;
15495  } else if (s == 1) {
15496  nextmove = RMOVE;
15497  } else {
15498  nextmove = LMOVE;
15499  }
15500  } else {
15501  // Two tets, below horizon and below right, are viable.
15502  if (randomnation(2)) {
15503  nextmove = HMOVE;
15504  } else {
15505  nextmove = RMOVE;
15506  }
15507  }
15508  } else {
15509  if (lori > 0) {
15510  // Two tets, below horizon and below left, are viable.
15511  if (randomnation(2)) {
15512  nextmove = HMOVE;
15513  } else {
15514  nextmove = LMOVE;
15515  }
15516  } else {
15517  // The tet below horizon is chosen.
15518  nextmove = HMOVE;
15519  }
15520  }
15521  } else {
15522  if (rori > 0) {
15523  if (lori > 0) {
15524  // Two tets, below right and below left, are viable.
15525  if (randomnation(2)) {
15526  nextmove = RMOVE;
15527  } else {
15528  nextmove = LMOVE;
15529  }
15530  } else {
15531  // The tet below right is chosen.
15532  nextmove = RMOVE;
15533  }
15534  } else {
15535  if (lori > 0) {
15536  // The tet below left is chosen.
15537  nextmove = LMOVE;
15538  } else {
15539  // 'endpt' lies either on the plane(s) or across face bcd.
15540  if (hori == 0) {
15541  if (rori == 0) {
15542  // pa->'endpt' is COLLINEAR with pa->pb.
15543  return ACROSSVERT;
15544  }
15545  if (lori == 0) {
15546  // pa->'endpt' is COLLINEAR with pa->pc.
15547  eprevesymself(*searchtet); // [a,c,d]
15548  return ACROSSVERT;
15549  }
15550  // pa->'endpt' crosses the edge pb->pc.
15551  return ACROSSEDGE;
15552  }
15553  if (rori == 0) {
15554  if (lori == 0) {
15555  // pa->'endpt' is COLLINEAR with pa->pd.
15556  esymself(*searchtet); // face bad.
15557  enextself(*searchtet); // face [a,d,b]
15558  return ACROSSVERT;
15559  }
15560  // pa->'endpt' crosses the edge pb->pd.
15561  esymself(*searchtet); // face bad.
15562  enextself(*searchtet); // face adb
15563  return ACROSSEDGE;
15564  }
15565  if (lori == 0) {
15566  // pa->'endpt' crosses the edge pc->pd.
15567  eprevesymself(*searchtet); // [a,c,d]
15568  return ACROSSEDGE;
15569  }
15570  // pa->'endpt' crosses the face bcd.
15571  return ACROSSFACE;
15572  }
15573  }
15574  }
15575 
15576  // Move to the next tet, fix pa as its origin.
15577  if (nextmove == RMOVE) {
15578  fnextself(*searchtet);
15579  } else if (nextmove == LMOVE) {
15580  eprevself(*searchtet);
15581  fnextself(*searchtet);
15582  enextself(*searchtet);
15583  } else { // HMOVE
15584  fsymself(*searchtet);
15585  enextself(*searchtet);
15586  }
15587  pb = dest(*searchtet);
15588  pc = apex(*searchtet);
15589 
15590  } // while (1)
15591 
15592 }
15593 
15595 // //
15596 // scoutsegment() Search an edge in the tetrahedralization. //
15597 // //
15598 // If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the //
15599 // edge from startpt to endpt. //
15600 // //
15601 // If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
15602 // indicates that the edge intersects an edge or a face. If 'refpt' is NULL,//
15603 // 'searchtet' returns the edge or face. If 'refpt' is not NULL, it returns //
15604 // a vertex which encroaches upon this edge, and 'searchtet' returns a tet //
15605 // which containing 'refpt'. //
15606 // //
15607 // The parameter 'sedge' is used to report self-intersection. It is the //
15608 // whose endpoints are 'startpt' and 'endpt'. It must not be a NULL.
15609 // //
15611 
15612 enum tetgenmesh::interresult tetgenmesh::scoutsegment(point startpt,point endpt,
15613  face *sedge, triface* searchtet, point* refpt, arraypool* intfacelist)
15614 {
15615  point pd;
15616  enum interresult dir;
15617  int t1ver;
15618 
15619  if (b->verbose > 2) {
15620  printf(" Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
15621  }
15622 
15623  point2tetorg(startpt, *searchtet);
15624  dir = finddirection(searchtet, endpt);
15625 
15626  if (dir == ACROSSVERT) {
15627  pd = dest(*searchtet);
15628  if (pd == endpt) {
15629  if (issubseg(*searchtet)) {
15630  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15631  }
15632  return SHAREEDGE;
15633  } else {
15634  // A point is on the path.
15635  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15636  return ACROSSVERT;
15637  }
15638  }
15639 
15640  // dir is either ACROSSEDGE or ACROSSFACE.
15641  enextesymself(*searchtet); // Go to the opposite face.
15642  fsymself(*searchtet); // Enter the adjacent tet.
15643 
15644  if (dir == ACROSSEDGE) {
15645  // Check whether two segments are intersecting.
15646  if (issubseg(*searchtet)) {
15647  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15648  }
15649  } else if (dir == ACROSSFACE) {
15650  if (checksubfaceflag) {
15651  // Check whether a segment and a subface are intersecting.
15652  if (issubface(*searchtet)) {
15653  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15654  }
15655  }
15656  } else {
15657  terminatetetgen(this, 2);
15658  }
15659 
15660  if (refpt == NULL) {
15661  // Do not need a reference point. Return.
15662  return dir;
15663  }
15664 
15665  triface neightet, reftet;
15666  point pa, pb, pc;
15667  REAL angmax, ang;
15668  int types[2], poss[4];
15669  int pos = 0, i, j;
15670 
15671  pa = org(*searchtet);
15672  angmax = interiorangle(pa, startpt, endpt, NULL);
15673  *refpt = pa;
15674  pb = dest(*searchtet);
15675  ang = interiorangle(pb, startpt, endpt, NULL);
15676  if (ang > angmax) {
15677  angmax = ang;
15678  *refpt = pb;
15679  }
15680  pc = apex(*searchtet);
15681  ang = interiorangle(pc, startpt, endpt, NULL);
15682  if (ang > angmax) {
15683  angmax = ang;
15684  *refpt = pc;
15685  }
15686  reftet = *searchtet; // Save the tet containing the refpt.
15687 
15688  // Search intersecting faces along the segment.
15689  while (1) {
15690 
15691 
15692  pd = oppo(*searchtet);
15693 
15694 
15695  // Stop if we meet 'endpt'.
15696  if (pd == endpt) break;
15697 
15698  ang = interiorangle(pd, startpt, endpt, NULL);
15699  if (ang > angmax) {
15700  angmax = ang;
15701  *refpt = pd;
15702  reftet = *searchtet;
15703  }
15704 
15705  // Find a face intersecting the segment.
15706  if (dir == ACROSSFACE) {
15707  // One of the three oppo faces in 'searchtet' intersects the segment.
15708  neightet = *searchtet;
15709  j = (neightet.ver & 3); // j is the current face number.
15710  for (i = j + 1; i < j + 4; i++) {
15711  neightet.ver = (i % 4);
15712  pa = org(neightet);
15713  pb = dest(neightet);
15714  pc = apex(neightet);
15715  pd = oppo(neightet); // The above point.
15716  if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15717  dir = (enum interresult) types[0];
15718  pos = poss[0];
15719  break;
15720  } else {
15721  dir = DISJOINT;
15722  pos = 0;
15723  }
15724  }
15725  } else if (dir == ACROSSEDGE) {
15726  // Check the two opposite faces (of the edge) in 'searchtet'.
15727  for (i = 0; i < 2; i++) {
15728  if (i == 0) {
15729  enextesym(*searchtet, neightet);
15730  } else {
15731  eprevesym(*searchtet, neightet);
15732  }
15733  pa = org(neightet);
15734  pb = dest(neightet);
15735  pc = apex(neightet);
15736  pd = oppo(neightet); // The above point.
15737  if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15738  dir = (enum interresult) types[0];
15739  pos = poss[0];
15740  break;
15741  } else {
15742  dir = DISJOINT;
15743  pos = 0;
15744  }
15745  }
15746  if (dir == DISJOINT) {
15747  // No intersection. Rotate to the next tet at the edge.
15748  dir = ACROSSEDGE;
15749  fnextself(*searchtet);
15750  continue;
15751  }
15752  }
15753 
15754  if (dir == ACROSSVERT) {
15755  // This segment passing a vertex. Choose it and return.
15756  for (i = 0; i < pos; i++) {
15757  enextself(neightet);
15758  }
15759  eprev(neightet, *searchtet);
15760  // dest(*searchtet) lies on the segment.
15761  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15762  return ACROSSVERT;
15763  } else if (dir == ACROSSEDGE) {
15764  // Get the edge intersects with the segment.
15765  for (i = 0; i < pos; i++) {
15766  enextself(neightet);
15767  }
15768  }
15769  // Go to the next tet.
15770  fsym(neightet, *searchtet);
15771 
15772  if (dir == ACROSSEDGE) {
15773  // Check whether two segments are intersecting.
15774  if (issubseg(*searchtet)) {
15775  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15776  }
15777  } else if (dir == ACROSSFACE) {
15778  if (checksubfaceflag) {
15779  // Check whether a segment and a subface are intersecting.
15780  if (issubface(*searchtet)) {
15781  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15782  }
15783  }
15784  } else {
15785  terminatetetgen(this, 2);
15786  }
15787 
15788  } // while (1)
15789 
15790  // A valid reference point should inside the diametrial circumsphere of
15791  // the missing segment, i.e., it encroaches upon it.
15792  if (2.0 * angmax < PI) {
15793  *refpt = NULL;
15794  }
15795 
15796 
15797  *searchtet = reftet;
15798  return dir;
15799 }
15800 
15802 // //
15803 // getsteinerpointonsegment() Get a Steiner point on a segment. //
15804 // //
15805 // Return '1' if 'refpt' lies on an adjacent segment of this segment. Other- //
15806 // wise, return '0'. //
15807 // //
15809 
15810 int tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
15811 {
15812  point ei = sorg(*seg);
15813  point ej = sdest(*seg);
15814  int adjflag = 0, i;
15815 
15816  if (refpt != NULL) {
15817  REAL L, L1, t;
15818 
15819  if (pointtype(refpt) == FREESEGVERTEX) {
15820  face parentseg;
15821  sdecode(point2sh(refpt), parentseg);
15822  int sidx1 = getfacetindex(parentseg);
15823  point far_pi = segmentendpointslist[sidx1 * 2];
15824  point far_pj = segmentendpointslist[sidx1 * 2 + 1];
15825  int sidx2 = getfacetindex(*seg);
15826  point far_ei = segmentendpointslist[sidx2 * 2];
15827  point far_ej = segmentendpointslist[sidx2 * 2 + 1];
15828  if ((far_pi == far_ei) || (far_pj == far_ei)) {
15829  // Create a Steiner point at the intersection of the segment
15830  // [far_ei, far_ej] and the sphere centered at far_ei with
15831  // radius |far_ei - refpt|.
15832  L = distance(far_ei, far_ej);
15833  L1 = distance(far_ei, refpt);
15834  t = L1 / L;
15835  for (i = 0; i < 3; i++) {
15836  steinpt[i] = far_ei[i] + t * (far_ej[i] - far_ei[i]);
15837  }
15838  adjflag = 1;
15839  } else if ((far_pi == far_ej) || (far_pj == far_ej)) {
15840  L = distance(far_ei, far_ej);
15841  L1 = distance(far_ej, refpt);
15842  t = L1 / L;
15843  for (i = 0; i < 3; i++) {
15844  steinpt[i] = far_ej[i] + t * (far_ei[i] - far_ej[i]);
15845  }
15846  adjflag = 1;
15847  } else {
15848  // Cut the segment by the projection point of refpt.
15849  projpt2edge(refpt, ei, ej, steinpt);
15850  }
15851  } else {
15852  // Cut the segment by the projection point of refpt.
15853  projpt2edge(refpt, ei, ej, steinpt);
15854  }
15855 
15856  // Make sure that steinpt is not too close to ei and ej.
15857  L = distance(ei, ej);
15858  L1 = distance(steinpt, ei);
15859  t = L1 / L;
15860  if ((t < 0.2) || (t > 0.8)) {
15861  // Split the point at the middle.
15862  for (i = 0; i < 3; i++) {
15863  steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15864  }
15865  }
15866  } else {
15867  // Split the point at the middle.
15868  for (i = 0; i < 3; i++) {
15869  steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15870  }
15871  }
15872 
15873 
15874  return adjflag;
15875 }
15876 
15877 
15878 
15880 // //
15881 // delaunizesegments() Recover segments in a DT. //
15882 // //
15883 // All segments need to be recovered are in 'subsegstack' (Q). They will be //
15884 // be recovered one by one (in a random order). //
15885 // //
15886 // Given a segment s in the Q, this routine first queries s in the DT, if s //
15887 // matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split //
15888 // by inserting a new point p in both the DT and itself. The two new subseg- //
15889 // ments of s are queued in Q. The process continues until Q is empty. //
15890 // //
15892 
15893 void tetgenmesh::delaunizesegments()
15894 {
15895  triface searchtet, spintet;
15896  face searchsh;
15897  face sseg, *psseg;
15898  point refpt, newpt;
15899  enum interresult dir;
15900  insertvertexflags ivf;
15901  int t1ver;
15902 
15903 
15904  ivf.bowywat = 1; // Use Bowyer-Watson insertion.
15905  ivf.sloc = (int) ONEDGE; // on 'sseg'.
15906  ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
15907  ivf.assignmeshsize = b->metric;
15908  ivf.smlenflag = useinsertradius; // Return the closet mesh vertex.
15909 
15910  // Loop until 'subsegstack' is empty.
15911  while (subsegstack->objects > 0l) {
15912  // seglist is used as a stack.
15913  subsegstack->objects--;
15914  psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
15915  sseg = *psseg;
15916 
15917  // Check if this segment has been recovered.
15918  sstpivot1(sseg, searchtet);
15919  if (searchtet.tet != NULL) {
15920  continue; // Not a missing segment.
15921  }
15922 
15923  // Search the segment.
15924  dir = scoutsegment(sorg(sseg), sdest(sseg), &sseg,&searchtet,&refpt,NULL);
15925 
15926  if (dir == SHAREEDGE) {
15927  // Found this segment, insert it.
15928  // Let the segment remember an adjacent tet.
15929  sstbond1(sseg, searchtet);
15930  // Bond the segment to all tets containing it.
15931  spintet = searchtet;
15932  do {
15933  tssbond1(spintet, sseg);
15934  fnextself(spintet);
15935  } while (spintet.tet != searchtet.tet);
15936  } else {
15937  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15938  // The segment is missing. Split it.
15939  // Create a new point.
15940  makepoint(&newpt, FREESEGVERTEX);
15941  //setpointtype(newpt, FREESEGVERTEX);
15942  getsteinerptonsegment(&sseg, refpt, newpt);
15943 
15944  // Start searching from 'searchtet'.
15945  ivf.iloc = (int) OUTSIDE;
15946  // Insert the new point into the tetrahedralization T.
15947  // Missing segments and subfaces are queued for recovery.
15948  // Note that T is convex (nonconvex = 0).
15949  if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
15950  // The new point has been inserted.
15951  st_segref_count++;
15952  if (steinerleft > 0) steinerleft--;
15953  if (useinsertradius) {
15954  save_segmentpoint_insradius(newpt, ivf.parentpt, ivf.smlen);
15955  }
15956  } else {
15957  if (ivf.iloc == (int) NEARVERTEX) {
15958  // The new point (in the segment) is very close to an existing
15959  // vertex -- a small feature is detected.
15960  point nearpt = org(searchtet);
15961  if (pointtype(nearpt) == FREESEGVERTEX) {
15962  face parentseg;
15963  sdecode(point2sh(nearpt), parentseg);
15964  point p1 = farsorg(sseg);
15965  point p2 = farsdest(sseg);
15966  point p3 = farsorg(parentseg);
15967  point p4 = farsdest(parentseg);
15968  printf("Two segments are very close to each other.\n");
15969  printf(" Segment 1: [%d, %d] #%d\n", pointmark(p1),
15970  pointmark(p2), shellmark(sseg));
15971  printf(" Segment 2: [%d, %d] #%d\n", pointmark(p3),
15972  pointmark(p4), shellmark(parentseg));
15973  terminatetetgen(this, 4);
15974  } else {
15975  terminatetetgen(this, 2);
15976  }
15977  } else if (ivf.iloc == (int) ONVERTEX) {
15978  // The new point (in the segment) is coincident with an existing
15979  // vertex -- a self-intersection is detected.
15980  eprevself(searchtet);
15981  report_selfint_edge(sorg(sseg), sdest(sseg), &sseg, &searchtet,
15982  ACROSSVERT);
15983  } else {
15984  // An unknown case. Report a bug.
15985  terminatetetgen(this, 2);
15986  }
15987  }
15988  } else {
15989  // An unknown case. Report a bug.
15990  terminatetetgen(this, 2);
15991  }
15992  }
15993  } // while
15994 }
15995 
15997 // //
15998 // scoutsubface() Search subface in the tetrahedralization. //
15999 // //
16000 // 'searchsh' is searched in T. If it exists, it is 'locked' at the face in //
16001 // T. 'searchtet' refers to the face. Otherwise, it is missing. //
16002 // //
16003 // The parameter 'shflag' indicates whether 'searchsh' is a boundary face or //
16004 // not. It is possible that 'searchsh' is a temporarily subface that is used //
16005 // as a cavity boundary face. //
16006 // //
16008 
16009 int tetgenmesh::scoutsubface(face* searchsh, triface* searchtet, int shflag)
16010 {
16011  point pa = sorg(*searchsh);
16012  point pb = sdest(*searchsh);
16013 
16014  // Get a tet whose origin is a.
16015  point2tetorg(pa, *searchtet);
16016  // Search the edge [a,b].
16017  enum interresult dir = finddirection(searchtet, pb);
16018  if (dir == ACROSSVERT) {
16019  // Check validity of a PLC.
16020  if (dest(*searchtet) != pb) {
16021  if (shflag) {
16022  // A vertex lies on the search edge.
16023  report_selfint_edge(pa, pb, searchsh, searchtet, dir);
16024  } else {
16025  terminatetetgen(this, 2);
16026  }
16027  }
16028  int t1ver;
16029  // The edge exists. Check if the face exists.
16030  point pc = sapex(*searchsh);
16031  // Searchtet holds edge [a,b]. Search a face with apex c.
16032  triface spintet = *searchtet;
16033  while (1) {
16034  if (apex(spintet) == pc) {
16035  // Found a face matching to 'searchsh'!
16036  if (!issubface(spintet)) {
16037  // Insert 'searchsh'.
16038  tsbond(spintet, *searchsh);
16039  fsymself(spintet);
16040  sesymself(*searchsh);
16041  tsbond(spintet, *searchsh);
16042  *searchtet = spintet;
16043  return 1;
16044  } else {
16045  terminatetetgen(this, 2);
16046  }
16047  }
16048  fnextself(spintet);
16049  if (spintet.tet == searchtet->tet) break;
16050  }
16051  }
16052 
16053  return 0;
16054 }
16055 
16057 // //
16058 // formregion() Form the missing region of a missing subface. //
16059 // //
16060 // 'missh' is a missing subface. From it we form a missing region R which is //
16061 // a connected region formed by a set of missing subfaces of a facet. //
16062 // Comment: There should be no segment inside R. //
16063 // //
16064 // 'missingshs' returns the list of subfaces in R. All subfaces in this list //
16065 // are oriented as the 'missh'. 'missingshbds' returns the list of boundary //
16066 // edges (tetrahedral handles) of R. 'missingshverts' returns all vertices //
16067 // of R. They are all pmarktested. //
16068 // //
16069 // Except the first one (which is 'missh') in 'missingshs', each subface in //
16070 // this list represents an internal edge of R, i.e., it is missing in the //
16071 // tetrahedralization. Since R may contain interior vertices, not all miss- //
16072 // ing edges can be found by this way. //
16074 
16075 void tetgenmesh::formregion(face* missh, arraypool* missingshs,
16076  arraypool* missingshbds, arraypool* missingshverts)
16077 {
16078  triface searchtet, spintet;
16079  face neighsh, *parysh;
16080  face neighseg, fakeseg;
16081  point pa, pb, *parypt;
16082  enum interresult dir;
16083  int t1ver;
16084  int i, j;
16085 
16086  smarktest(*missh);
16087  missingshs->newindex((void **) &parysh);
16088  *parysh = *missh;
16089 
16090  // Incrementally find other missing subfaces.
16091  for (i = 0; i < missingshs->objects; i++) {
16092  missh = (face *) fastlookup(missingshs, i);
16093  for (j = 0; j < 3; j++) {
16094  pa = sorg(*missh);
16095  pb = sdest(*missh);
16096  point2tetorg(pa, searchtet);
16097  dir = finddirection(&searchtet, pb);
16098  if (dir != ACROSSVERT) {
16099  // This edge is missing. Its neighbor is a missing subface.
16100  spivot(*missh, neighsh);
16101  if (!smarktested(neighsh)) {
16102  // Adjust the face orientation.
16103  if (sorg(neighsh) != pb) sesymself(neighsh);
16104  smarktest(neighsh);
16105  missingshs->newindex((void **) &parysh);
16106  *parysh = neighsh;
16107  }
16108  } else {
16109  if (dest(searchtet) != pb) {
16110  // Report a PLC problem.
16111  report_selfint_edge(pa, pb, missh, &searchtet, dir);
16112  }
16113  }
16114  // Collect the vertices of R.
16115  if (!pmarktested(pa)) {
16116  pmarktest(pa);
16117  missingshverts->newindex((void **) &parypt);
16118  *parypt = pa;
16119  }
16120  senextself(*missh);
16121  } // j
16122  } // i
16123 
16124  // Get the boundary edges of R.
16125  for (i = 0; i < missingshs->objects; i++) {
16126  missh = (face *) fastlookup(missingshs, i);
16127  for (j = 0; j < 3; j++) {
16128  spivot(*missh, neighsh);
16129  if ((neighsh.sh == NULL) || !smarktested(neighsh)) {
16130  // A boundary edge of R.
16131  // Let the segment point to the adjacent tet.
16132  point2tetorg(sorg(*missh), searchtet);
16133  finddirection(&searchtet, sdest(*missh));
16134  missingshbds->newindex((void **) &parysh);
16135  *parysh = *missh;
16136  // Check if this edge is a segment.
16137  sspivot(*missh, neighseg);
16138  if (neighseg.sh == NULL) {
16139  // Temporarily create a segment at this edge.
16140  makeshellface(subsegs, &fakeseg);
16141  setsorg(fakeseg, sorg(*missh));
16142  setsdest(fakeseg, sdest(*missh));
16143  sinfect(fakeseg); // Mark it as faked.
16144  // Connect it to all tets at this edge.
16145  spintet = searchtet;
16146  while (1) {
16147  tssbond1(spintet, fakeseg);
16148  fnextself(spintet);
16149  if (spintet.tet == searchtet.tet) break;
16150  }
16151  neighseg = fakeseg;
16152  }
16153  // Let the segment and the boundary edge point to each other.
16154  ssbond(*missh, neighseg);
16155  sstbond1(neighseg, searchtet);
16156  }
16157  senextself(*missh);
16158  } // j
16159  } // i
16160 
16161 
16162  // Unmarktest collected missing subfaces.
16163  for (i = 0; i < missingshs->objects; i++) {
16164  parysh = (face *) fastlookup(missingshs, i);
16165  sunmarktest(*parysh);
16166  }
16167 }
16168 
16170 // //
16171 // scoutcrossedge() Search an edge that crosses the missing region. //
16172 // //
16173 // Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
16174 // over, the edge is oriented such that its origin lies below R. Return 0 //
16175 // if no such edge is found. //
16176 // //
16177 // Assumption: All vertices of the missing region are marktested. //
16178 // //
16180 
16181 int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds,
16182  arraypool* missingshs)
16183 {
16184  triface searchtet, spintet, neightet;
16185  face oldsh, searchsh, *parysh;
16186  face neighseg;
16187  point pa, pb, pc, pd, pe;
16188  REAL ori;
16189  int types[2], poss[4];
16190  int searchflag, interflag;
16191  int t1ver;
16192  int i, j;
16193 
16194  searchflag = 0;
16195 
16196  // Search the first new subface to fill the region.
16197  for (i = 0; i < missingshbds->objects && !searchflag; i++) {
16198  parysh = (face *) fastlookup(missingshbds, i);
16199  sspivot(*parysh, neighseg);
16200  sstpivot1(neighseg, searchtet);
16201  if (org(searchtet) != sorg(*parysh)) {
16202  esymself(searchtet);
16203  }
16204  spintet = searchtet;
16205  while (1) {
16206  if (pmarktested(apex(spintet))) {
16207  // A possible interior face.
16208  neightet = spintet;
16209  oldsh = *parysh;
16210  // Try to recover an interior edge.
16211  for (j = 0; j < 2; j++) {
16212  enextself(neightet);
16213  if (!issubseg(neightet)) {
16214  if (j == 0) {
16215  senext(oldsh, searchsh);
16216  } else {
16217  senext2(oldsh, searchsh);
16218  sesymself(searchsh);
16219  esymself(neightet);
16220  }
16221  // Calculate a lifted point.
16222  pa = sorg(searchsh);
16223  pb = sdest(searchsh);
16224  pc = sapex(searchsh);
16225  pd = dest(neightet);
16226  calculateabovepoint4(pa, pb, pc, pd);
16227  // The lifted point must lie above 'searchsh'.
16228  ori = orient3d(pa, pb, pc, dummypoint);
16229  if (ori > 0) {
16230  sesymself(searchsh);
16231  senextself(searchsh);
16232  } else if (ori == 0) {
16233  terminatetetgen(this, 2);
16234  }
16235  if (sscoutsegment(&searchsh,dest(neightet),0,0,1)==SHAREEDGE) {
16236  // Insert a temp segment to protect the recovered edge.
16237  face tmpseg;
16238  makeshellface(subsegs, &tmpseg);
16239  ssbond(searchsh, tmpseg);
16240  spivotself(searchsh);
16241  ssbond(searchsh, tmpseg);
16242  // Recover locally Delaunay edges.
16243  lawsonflip();
16244  // Delete the tmp segment.
16245  spivot(tmpseg, searchsh);
16246  ssdissolve(searchsh);
16247  spivotself(searchsh);
16248  ssdissolve(searchsh);
16249  shellfacedealloc(subsegs, tmpseg.sh);
16250  searchflag = 1;
16251  } else {
16252  // Undo the performed flips.
16253  if (flipstack != NULL) {
16254  lawsonflip();
16255  }
16256  }
16257  break;
16258  } // if (!issubseg(neightet))
16259  } // j
16260  if (searchflag) break;
16261  } // if (pmarktested(apex(spintet)))
16262  fnextself(spintet);
16263  if (spintet.tet == searchtet.tet) break;
16264  }
16265  } // i
16266 
16267  if (searchflag) {
16268  // Remove faked segments.
16269  face checkseg;
16270  // Remark: We should not use the array 'missingshbds', since the flips may
16271  // change the subfaces. We search them from the subfaces in R.
16272  for (i = 0; i < missingshs->objects; i++) {
16273  parysh = (face *) fastlookup(missingshs, i);
16274  oldsh = *parysh;
16275  for (j = 0; j < 3; j++) {
16276  if (isshsubseg(oldsh)) {
16277  sspivot(oldsh, checkseg);
16278  if (sinfected(checkseg)) {
16279  // It's a faked segment. Delete it.
16280  sstpivot1(checkseg, searchtet);
16281  spintet = searchtet;
16282  while (1) {
16283  tssdissolve1(spintet);
16284  fnextself(spintet);
16285  if (spintet.tet == searchtet.tet) break;
16286  }
16287  shellfacedealloc(subsegs, checkseg.sh);
16288  ssdissolve(oldsh);
16289  }
16290  }
16291  senextself(oldsh);
16292  } // j
16293  }
16294 
16295  fillregioncount++;
16296 
16297  return 0;
16298  } // if (i < missingshbds->objects)
16299 
16300  searchflag = -1;
16301 
16302  for (j = 0; j < missingshbds->objects && (searchflag == -1); j++) {
16303  parysh = (face *) fastlookup(missingshbds, j);
16304  sspivot(*parysh, neighseg);
16305  sstpivot1(neighseg, searchtet);
16306  interflag = 0;
16307  // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
16308  spintet = searchtet;
16309  while (1) {
16310  pd = apex(spintet);
16311  pe = oppo(spintet);
16312  // Skip a hull edge.
16313  if ((pd != dummypoint) && (pe != dummypoint)) {
16314  // Skip an edge containing a vertex of R.
16315  if (!pmarktested(pd) && !pmarktested(pe)) {
16316  // Check if [d,e] intersects R.
16317  for (i = 0; i < missingshs->objects && !interflag; i++) {
16318  parysh = (face *) fastlookup(missingshs, i);
16319  pa = sorg(*parysh);
16320  pb = sdest(*parysh);
16321  pc = sapex(*parysh);
16322  interflag=tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
16323  if (interflag > 0) {
16324  if (interflag == 2) {
16325  // They intersect at a single point.
16326  if ((types[0] == (int) ACROSSFACE) ||
16327  (types[0] == (int) ACROSSEDGE)) {
16328  // Go to the crossing edge [d,e,#,#].
16329  edestoppo(spintet, crosstet); // // [d,e,#,#].
16330  if (issubseg(crosstet)) {
16331  // It is a segment. Report a PLC problem.
16332  report_selfint_face(pa, pb, pc, parysh, &crosstet,
16333  interflag, types, poss);
16334  } else {
16335  triface chkface = crosstet;
16336  while (1) {
16337  if (issubface(chkface)) break;
16338  fsymself(chkface);
16339  if (chkface.tet == crosstet.tet) break;
16340  }
16341  if (issubface(chkface)) {
16342  // Two subfaces are intersecting.
16343  report_selfint_face(pa, pb, pc, parysh, &chkface,
16344  interflag, types, poss);
16345  }
16346  }
16347  // Adjust the edge such that d lies below [a,b,c].
16348  ori = orient3d(pa, pb, pc, pd);
16349  if (ori < 0) {
16350  esymself(crosstet);
16351  }
16352  searchflag = 1;
16353  } else {
16354  // An improper intersection type, ACROSSVERT, TOUCHFACE,
16355  // TOUCHEDGE, SHAREVERT, ...
16356  // Maybe it is due to a PLC problem.
16357  report_selfint_face(pa, pb, pc, parysh, &crosstet,
16358  interflag, types, poss);
16359  }
16360  }
16361  break;
16362  } // if (interflag > 0)
16363  }
16364  }
16365  }
16366  // Leave search at this bdry edge if an intersection is found.
16367  if (interflag > 0) break;
16368  // Go to the next tetrahedron.
16369  fnextself(spintet);
16370  if (spintet.tet == searchtet.tet) break;
16371  } // while (1)
16372  } // j
16373 
16374  return searchflag;
16375 }
16376 
16378 // //
16379 // formcavity() Form the cavity of a missing region. //
16380 // //
16381 // The missing region R is formed by a set of missing subfaces 'missingshs'. //
16382 // In the following, we assume R is horizontal and oriented. (All subfaces //
16383 // of R are oriented in the same way.) 'searchtet' is a tetrahedron [d,e,#, //
16384 // #] which intersects R in its interior, where the edge [d,e] intersects R, //
16385 // and d lies below R. //
16386 // //
16387 // 'crosstets' returns the set of crossing tets. Every tet in it has the //
16388 // form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R. The //
16389 // set of tets form the cavity C, which is divided into two parts by R, one //
16390 // at top and one at bottom. 'topfaces' and 'botfaces' return the upper and //
16391 // lower boundary faces of C. 'toppoints' contains vertices of 'crosstets' //
16392 // in the top part of C, and so does 'botpoints'. Both 'toppoints' and //
16393 // 'botpoints' contain vertices of R. //
16394 // //
16395 // Important: This routine assumes all vertices of the facet containing this //
16396 // subface are marked, i.e., pmarktested(p) returns true. //
16397 // //
16399 
16400 bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
16401  arraypool* crosstets, arraypool* topfaces,
16402  arraypool* botfaces, arraypool* toppoints,
16403  arraypool* botpoints)
16404 {
16405  arraypool *crossedges;
16406  triface spintet, neightet, chkface, *parytet;
16407  face *parysh = NULL;
16408  point pa, pd, pe, *parypt;
16409  bool testflag, invalidflag;
16410  int intflag, types[2], poss[4];
16411  int t1ver;
16412  int i, j, k;
16413 
16414  // Temporarily re-use 'topfaces' for all crossing edges.
16415  crossedges = topfaces;
16416 
16417  if (b->verbose > 2) {
16418  printf(" Form the cavity of a missing region.\n");
16419  }
16420  // Mark this edge to avoid testing it later.
16421  markedge(*searchtet);
16422  crossedges->newindex((void **) &parytet);
16423  *parytet = *searchtet;
16424 
16425  invalidflag = 0;
16426  // Collect all crossing tets. Each cross tet is saved in the standard
16427  // form [d,e,#,#], where [d,e] is a crossing edge, d lies below R.
16428  // NEITHER d NOR e is a vertex of R (!pmarktested).
16429  for (i = 0; i < crossedges->objects && !invalidflag; i++) {
16430  // Get a crossing edge [d,e,#,#].
16431  searchtet = (triface *) fastlookup(crossedges, i);
16432  // Sort vertices into the bottom and top arrays.
16433  pd = org(*searchtet);
16434  if (!pinfected(pd)) {
16435  pinfect(pd);
16436  botpoints->newindex((void **) &parypt);
16437  *parypt = pd;
16438  }
16439  pe = dest(*searchtet);
16440  if (!pinfected(pe)) {
16441  pinfect(pe);
16442  toppoints->newindex((void **) &parypt);
16443  *parypt = pe;
16444  }
16445 
16446  // All tets sharing this edge are crossing tets.
16447  spintet = *searchtet;
16448  while (1) {
16449  if (!infected(spintet)) {
16450  infect(spintet);
16451  crosstets->newindex((void **) &parytet);
16452  *parytet = spintet;
16453  }
16454  // Go to the next crossing tet.
16455  fnextself(spintet);
16456  if (spintet.tet == searchtet->tet) break;
16457  } // while (1)
16458 
16459  // Detect new crossing edges.
16460  spintet = *searchtet;
16461  while (1) {
16462  // spintet is [d,e,a,#], where d lies below R, and e lies above R.
16463  pa = apex(spintet);
16464  if (pa != dummypoint) {
16465  if (!pmarktested(pa)) {
16466  // There exists a crossing edge, either [e,a] or [a,d]. First check
16467  // if the crossing edge has already be added, i.e.,to check if one
16468  // of the tetrahedron at this edge has been marked.
16469  testflag = true;
16470  for (j = 0; j < 2 && testflag; j++) {
16471  if (j == 0) {
16472  enext(spintet, neightet);
16473  } else {
16474  eprev(spintet, neightet);
16475  }
16476  while (1) {
16477  if (edgemarked(neightet)) {
16478  // This crossing edge has already been tested. Skip it.
16479  testflag = false;
16480  break;
16481  }
16482  fnextself(neightet);
16483  if (neightet.tet == spintet.tet) break;
16484  }
16485  } // j
16486  if (testflag) {
16487  // Test if [e,a] or [a,d] intersects R.
16488  // Do a brute-force search in the set of subfaces of R. Slow!
16489  // Need to be improved!
16490  pd = org(spintet);
16491  pe = dest(spintet);
16492  for (k = 0; k < missingshs->objects; k++) {
16493  parysh = (face *) fastlookup(missingshs, k);
16494  intflag = tri_edge_test(sorg(*parysh), sdest(*parysh),
16495  sapex(*parysh), pe, pa, NULL, 1, types, poss);
16496  if (intflag > 0) {
16497  // Found intersection. 'a' lies below R.
16498  if (intflag == 2) {
16499  enext(spintet, neightet);
16500  if ((types[0] == (int) ACROSSFACE) ||
16501  (types[0] == (int) ACROSSEDGE)) {
16502  // Only this case is valid.
16503  } else {
16504  // A non-valid intersection. Maybe a PLC problem.
16505  invalidflag = 1;
16506  }
16507  } else {
16508  // Coplanar intersection. Maybe a PLC problem.
16509  invalidflag = 1;
16510  }
16511  break;
16512  }
16513  intflag = tri_edge_test(sorg(*parysh), sdest(*parysh),
16514  sapex(*parysh), pa, pd, NULL, 1, types, poss);
16515  if (intflag > 0) {
16516  // Found intersection. 'a' lies above R.
16517  if (intflag == 2) {
16518  eprev(spintet, neightet);
16519  if ((types[0] == (int) ACROSSFACE) ||
16520  (types[0] == (int) ACROSSEDGE)) {
16521  // Only this case is valid.
16522  } else {
16523  // A non-valid intersection. Maybe a PLC problem.
16524  invalidflag = 1;
16525  }
16526  } else {
16527  // Coplanar intersection. Maybe a PLC problem.
16528  invalidflag = 1;
16529  }
16530  break;
16531  }
16532  } // k
16533  if (k < missingshs->objects) {
16534  // Found a pair of triangle - edge intersection.
16535  if (invalidflag) {
16536  break; // the while (1) loop
16537  }
16538  // Adjust the edge direction, so that its origin lies below R,
16539  // and its destination lies above R.
16540  esymself(neightet);
16541  // This edge may be a segment.
16542  if (issubseg(neightet)) {
16543  report_selfint_face(sorg(*parysh), sdest(*parysh),
16544  sapex(*parysh),parysh,&neightet,intflag,types,poss);
16545  }
16546  // Check if it is an edge of a subface.
16547  chkface = neightet;
16548  while (1) {
16549  if (issubface(chkface)) break;
16550  fsymself(chkface);
16551  if (chkface.tet == neightet.tet) break;
16552  }
16553  if (issubface(chkface)) {
16554  // Two subfaces are intersecting.
16555  report_selfint_face(sorg(*parysh), sdest(*parysh),
16556  sapex(*parysh),parysh,&chkface,intflag,types,poss);
16557  }
16558 
16559  // Mark this edge to avoid testing it again.
16560  markedge(neightet);
16561  crossedges->newindex((void **) &parytet);
16562  *parytet = neightet;
16563  } else {
16564  // No intersection is found. It may be a PLC problem.
16565  invalidflag = 1;
16566  break; // the while (1) loop
16567  } // if (k == missingshs->objects)
16568  } // if (testflag)
16569  }
16570  } // if (pa != dummypoint)
16571  // Go to the next crossing tet.
16572  fnextself(spintet);
16573  if (spintet.tet == searchtet->tet) break;
16574  } // while (1)
16575  } // i
16576 
16577  // Unmark all marked edges.
16578  for (i = 0; i < crossedges->objects; i++) {
16579  searchtet = (triface *) fastlookup(crossedges, i);
16580  unmarkedge(*searchtet);
16581  }
16582  crossedges->restart();
16583 
16584 
16585  if (invalidflag) {
16586  // Unmark all collected tets.
16587  for (i = 0; i < crosstets->objects; i++) {
16588  searchtet = (triface *) fastlookup(crosstets, i);
16589  uninfect(*searchtet);
16590  }
16591  // Unmark all collected vertices.
16592  for (i = 0; i < botpoints->objects; i++) {
16593  parypt = (point *) fastlookup(botpoints, i);
16594  puninfect(*parypt);
16595  }
16596  for (i = 0; i < toppoints->objects; i++) {
16597  parypt = (point *) fastlookup(toppoints, i);
16598  puninfect(*parypt);
16599  }
16600  crosstets->restart();
16601  botpoints->restart();
16602  toppoints->restart();
16603 
16604  // Randomly split an interior edge of R.
16605  i = randomnation(missingshs->objects - 1);
16606  recentsh = * (face *) fastlookup(missingshs, i);
16607  return false;
16608  }
16609 
16610  if (b->verbose > 2) {
16611  printf(" Formed cavity: %ld (%ld) cross tets (edges).\n",
16612  crosstets->objects, crossedges->objects);
16613  }
16614 
16615  // Collect the top and bottom faces and the middle vertices. Since all top
16616  // and bottom vertices have been infected. Uninfected vertices must be
16617  // middle vertices (i.e., the vertices of R).
16618  // NOTE 1: Hull tets may be collected. Process them as a normal one.
16619  // NOTE 2: Some previously recovered subfaces may be completely inside the
16620  // cavity. In such case, we remove these subfaces from the cavity and put
16621  // them into 'subfacstack'. They will be recovered later.
16622  // NOTE 3: Some segments may be completely inside the cavity, e.g., they
16623  // attached to a subface which is inside the cavity. Such segments are
16624  // put in 'subsegstack'. They will be recovered later.
16625  // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
16626  // are identified in the routine "carvecavity()".
16627 
16628  for (i = 0; i < crosstets->objects; i++) {
16629  searchtet = (triface *) fastlookup(crosstets, i);
16630  // searchtet is [d,e,a,b].
16631  eorgoppo(*searchtet, spintet);
16632  fsym(spintet, neightet); // neightet is [a,b,e,#]
16633  if (!infected(neightet)) {
16634  // A top face.
16635  topfaces->newindex((void **) &parytet);
16636  *parytet = neightet;
16637  }
16638  edestoppo(*searchtet, spintet);
16639  fsym(spintet, neightet); // neightet is [b,a,d,#]
16640  if (!infected(neightet)) {
16641  // A bottom face.
16642  botfaces->newindex((void **) &parytet);
16643  *parytet = neightet;
16644  }
16645  // Add middle vertices if there are (skip dummypoint).
16646  pa = org(neightet);
16647  if (!pinfected(pa)) {
16648  if (pa != dummypoint) {
16649  pinfect(pa);
16650  botpoints->newindex((void **) &parypt);
16651  *parypt = pa;
16652  toppoints->newindex((void **) &parypt);
16653  *parypt = pa;
16654  }
16655  }
16656  pa = dest(neightet);
16657  if (!pinfected(pa)) {
16658  if (pa != dummypoint) {
16659  pinfect(pa);
16660  botpoints->newindex((void **) &parypt);
16661  *parypt = pa;
16662  toppoints->newindex((void **) &parypt);
16663  *parypt = pa;
16664  }
16665  }
16666  } // i
16667 
16668  // Uninfect all collected top, bottom, and middle vertices.
16669  for (i = 0; i < toppoints->objects; i++) {
16670  parypt = (point *) fastlookup(toppoints, i);
16671  puninfect(*parypt);
16672  }
16673  for (i = 0; i < botpoints->objects; i++) {
16674  parypt = (point *) fastlookup(botpoints, i);
16675  puninfect(*parypt);
16676  }
16677  cavitycount++;
16678 
16679  return true;
16680 }
16681 
16683 // //
16684 // delaunizecavity() Fill a cavity by Delaunay tetrahedra. //
16685 // //
16686 // The cavity C to be tetrahedralized is the top or bottom part of a whole //
16687 // cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
16688 // faces' do not form a closed polyhedron. The "open" side are subfaces of //
16689 // the missing facet. These faces will be recovered later in fillcavity(). //
16690 // //
16691 // This routine first constructs the DT of the vertices. Then it identifies //
16692 // the half boundary faces of the cavity in DT. Possiblely the cavity C will //
16693 // be enlarged. //
16694 // //
16695 // The DT is returned in 'newtets'. //
16696 // //
16698 
16699 void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
16700  arraypool *cavshells, arraypool *newtets,
16701  arraypool *crosstets, arraypool *misfaces)
16702 {
16703  triface searchtet, neightet, *parytet, *parytet1;
16704  face tmpsh, *parysh;
16705  point pa, pb, pc, pd, pt[3], *parypt;
16706  insertvertexflags ivf;
16707  REAL ori;
16708  long baknum, bakhullsize;
16709  int bakchecksubsegflag, bakchecksubfaceflag;
16710  int t1ver;
16711  int i, j;
16712 
16713  if (b->verbose > 2) {
16714  printf(" Delaunizing cavity: %ld points, %ld faces.\n",
16715  cavpoints->objects, cavfaces->objects);
16716  }
16717  // Remember the current number of crossing tets. It may be enlarged later.
16718  baknum = crosstets->objects;
16719  bakhullsize = hullsize;
16720  bakchecksubsegflag = checksubsegflag;
16721  bakchecksubfaceflag = checksubfaceflag;
16722  hullsize = 0l;
16723  checksubsegflag = 0;
16724  checksubfaceflag = 0;
16725  b->verbose--; // Suppress informations for creating Delaunay tetra.
16726  b->plc = 0; // Do not check near vertices.
16727 
16728  ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
16729 
16730  // Get four non-coplanar points (no dummypoint).
16731  pa = pb = pc = NULL;
16732  for (i = 0; i < cavfaces->objects; i++) {
16733  parytet = (triface *) fastlookup(cavfaces, i);
16734  parytet->ver = epivot[parytet->ver];
16735  if (apex(*parytet) != dummypoint) {
16736  pa = org(*parytet);
16737  pb = dest(*parytet);
16738  pc = apex(*parytet);
16739  break;
16740  }
16741  }
16742  pd = NULL;
16743  for (; i < cavfaces->objects; i++) {
16744  parytet = (triface *) fastlookup(cavfaces, i);
16745  pt[0] = org(*parytet);
16746  pt[1] = dest(*parytet);
16747  pt[2] = apex(*parytet);
16748  for (j = 0; j < 3; j++) {
16749  if (pt[j] != dummypoint) { // Do not include a hull point.
16750  ori = orient3d(pa, pb, pc, pt[j]);
16751  if (ori != 0) {
16752  pd = pt[j];
16753  if (ori > 0) { // Swap pa and pb.
16754  pt[j] = pa; pa = pb; pb = pt[j];
16755  }
16756  break;
16757  }
16758  }
16759  }
16760  if (pd != NULL) break;
16761  }
16762 
16763  // Create an init DT.
16764  initialdelaunay(pa, pb, pc, pd);
16765 
16766  // Incrementally insert the vertices (duplicated vertices are ignored).
16767  for (i = 0; i < cavpoints->objects; i++) {
16768  pt[0] = * (point *) fastlookup(cavpoints, i);
16769  searchtet = recenttet;
16770  ivf.iloc = (int) OUTSIDE;
16771  insertpoint(pt[0], &searchtet, NULL, NULL, &ivf);
16772  }
16773 
16774  if (b->verbose > 2) {
16775  printf(" Identifying %ld boundary faces of the cavity.\n",
16776  cavfaces->objects);
16777  }
16778 
16779  while (1) {
16780 
16781  // Identify boundary faces. Mark interior tets. Save missing faces.
16782  for (i = 0; i < cavfaces->objects; i++) {
16783  parytet = (triface *) fastlookup(cavfaces, i);
16784  // Skip an interior face (due to the enlargement of the cavity).
16785  if (infected(*parytet)) continue;
16786  parytet->ver = epivot[parytet->ver];
16787  pt[0] = org(*parytet);
16788  pt[1] = dest(*parytet);
16789  pt[2] = apex(*parytet);
16790  // Create a temp subface.
16791  makeshellface(subfaces, &tmpsh);
16792  setshvertices(tmpsh, pt[0], pt[1], pt[2]);
16793  // Insert tmpsh in DT.
16794  searchtet.tet = NULL;
16795  if (scoutsubface(&tmpsh, &searchtet, 0)) { // shflag = 0
16796  // Inserted! 'tmpsh' must face toward the inside of the cavity.
16797  // Remember the boundary tet (outside the cavity) in tmpsh
16798  // (use the adjacent tet slot).
16799  tmpsh.sh[0] = (shellface) encode(*parytet);
16800  // Save this subface.
16801  cavshells->newindex((void **) &parysh);
16802  *parysh = tmpsh;
16803  }
16804  else {
16805  // This boundary face is missing.
16806  shellfacedealloc(subfaces, tmpsh.sh);
16807  // Save this face in list.
16808  misfaces->newindex((void **) &parytet1);
16809  *parytet1 = *parytet;
16810  }
16811  } // i
16812 
16813  if (misfaces->objects > 0) {
16814  if (b->verbose > 2) {
16815  printf(" Enlarging the cavity. %ld missing bdry faces\n",
16816  misfaces->objects);
16817  }
16818 
16819  // Removing all temporary subfaces.
16820  for (i = 0; i < cavshells->objects; i++) {
16821  parysh = (face *) fastlookup(cavshells, i);
16822  stpivot(*parysh, neightet);
16823  tsdissolve(neightet); // Detach it from adj. tets.
16824  fsymself(neightet);
16825  tsdissolve(neightet);
16826  shellfacedealloc(subfaces, parysh->sh);
16827  }
16828  cavshells->restart();
16829 
16830  // Infect the points which are of the cavity.
16831  for (i = 0; i < cavpoints->objects; i++) {
16832  pt[0] = * (point *) fastlookup(cavpoints, i);
16833  pinfect(pt[0]); // Mark it as inserted.
16834  }
16835 
16836  // Enlarge the cavity.
16837  for (i = 0; i < misfaces->objects; i++) {
16838  // Get a missing face.
16839  parytet = (triface *) fastlookup(misfaces, i);
16840  if (!infected(*parytet)) {
16841  // Put it into crossing tet list.
16842  infect(*parytet);
16843  crosstets->newindex((void **) &parytet1);
16844  *parytet1 = *parytet;
16845  // Insert the opposite point if it is not in DT.
16846  pd = oppo(*parytet);
16847  if (!pinfected(pd)) {
16848  searchtet = recenttet;
16849  ivf.iloc = (int) OUTSIDE;
16850  insertpoint(pd, &searchtet, NULL, NULL, &ivf);
16851  pinfect(pd);
16852  cavpoints->newindex((void **) &parypt);
16853  *parypt = pd;
16854  }
16855  // Add three opposite faces into the boundary list.
16856  for (j = 0; j < 3; j++) {
16857  esym(*parytet, neightet);
16858  fsymself(neightet);
16859  if (!infected(neightet)) {
16860  cavfaces->newindex((void **) &parytet1);
16861  *parytet1 = neightet;
16862  }
16863  enextself(*parytet);
16864  } // j
16865  } // if (!infected(parytet))
16866  } // i
16867 
16868  // Uninfect the points which are of the cavity.
16869  for (i = 0; i < cavpoints->objects; i++) {
16870  pt[0] = * (point *) fastlookup(cavpoints, i);
16871  puninfect(pt[0]);
16872  }
16873 
16874  misfaces->restart();
16875  continue;
16876  } // if (misfaces->objects > 0)
16877 
16878  break;
16879 
16880  } // while (1)
16881 
16882  // Collect all tets of the DT. All new tets are marktested.
16883  marktest(recenttet);
16884  newtets->newindex((void **) &parytet);
16885  *parytet = recenttet;
16886  for (i = 0; i < newtets->objects; i++) {
16887  searchtet = * (triface *) fastlookup(newtets, i);
16888  for (j = 0; j < 4; j++) {
16889  decode(searchtet.tet[j], neightet);
16890  if (!marktested(neightet)) {
16891  marktest(neightet);
16892  newtets->newindex((void **) &parytet);
16893  *parytet = neightet;
16894  }
16895  }
16896  }
16897 
16898  cavpoints->restart();
16899  cavfaces->restart();
16900 
16901  if (crosstets->objects > baknum) {
16902  // The cavity has been enlarged.
16903  cavityexpcount++;
16904  }
16905 
16906  // Restore the original values.
16907  hullsize = bakhullsize;
16908  checksubsegflag = bakchecksubsegflag;
16909  checksubfaceflag = bakchecksubfaceflag;
16910  b->verbose++;
16911  b->plc = 1;
16912 }
16913 
16915 // //
16916 // fillcavity() Fill new tets into the cavity. //
16917 // //
16918 // The new tets are stored in two disjoint sets(which share the same facet). //
16919 // 'topfaces' and 'botfaces' are the boundaries of these two sets, respect- //
16920 // ively. 'midfaces' is empty on input, and will store faces in the facet. //
16921 // //
16922 // Important: This routine assumes all vertices of the missing region R are //
16923 // marktested, i.e., pmarktested(p) returns true. //
16924 // //
16926 
16927 bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
16928  arraypool* midfaces, arraypool* missingshs,
16929  arraypool* topnewtets, arraypool* botnewtets,
16930  triface* crossedge)
16931 {
16932  arraypool *cavshells;
16933  triface bdrytet, neightet, *parytet;
16934  triface searchtet, spintet;
16935  face *parysh;
16936  face checkseg;
16937  point pa, pb, pc;
16938  bool mflag;
16939  int t1ver;
16940  int i, j;
16941 
16942  // Connect newtets to tets outside the cavity. These connections are needed
16943  // for identifying the middle faces (which belong to R).
16944  for (j = 0; j < 2; j++) {
16945  cavshells = (j == 0 ? topshells : botshells);
16946  if (cavshells != NULL) {
16947  for (i = 0; i < cavshells->objects; i++) {
16948  // Get a temp subface.
16949  parysh = (face *) fastlookup(cavshells, i);
16950  // Get the boundary tet outside the cavity (saved in sh[0]).
16951  decode(parysh->sh[0], bdrytet);
16952  pa = org(bdrytet);
16953  pb = dest(bdrytet);
16954  pc = apex(bdrytet);
16955  // Get the adjacent new tet inside the cavity.
16956  stpivot(*parysh, neightet);
16957  // Mark neightet as an interior tet of this cavity.
16958  infect(neightet);
16959  // Connect the two tets (the old connections are replaced).
16960  bond(bdrytet, neightet);
16961  tsdissolve(neightet); // Clear the pointer to tmpsh.
16962  // Update the point-to-tets map.
16963  setpoint2tet(pa, (tetrahedron) neightet.tet);
16964  setpoint2tet(pb, (tetrahedron) neightet.tet);
16965  setpoint2tet(pc, (tetrahedron) neightet.tet);
16966  } // i
16967  } // if (cavshells != NULL)
16968  } // j
16969 
16970  if (crossedge != NULL) {
16971  // Glue top and bottom tets at their common facet.
16972  triface toptet, bottet, spintet, *midface;
16973  point pd, pe;
16974  REAL ori;
16975  int types[2], poss[4];
16976  int interflag;
16977  int bflag;
16978 
16979  mflag = false;
16980  pd = org(*crossedge);
16981  pe = dest(*crossedge);
16982 
16983  // Search the first (middle) face in R.
16984  // Since R may be non-convex, we must make sure that the face is in the
16985  // interior of R. We search a face in 'topnewtets' whose three vertices
16986  // are on R and it intersects 'crossedge' in its interior. Then search
16987  // a matching face in 'botnewtets'.
16988  for (i = 0; i < topnewtets->objects && !mflag; i++) {
16989  searchtet = * (triface *) fastlookup(topnewtets, i);
16990  for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
16991  pa = org(searchtet);
16992  if (pmarktested(pa)) {
16993  pb = dest(searchtet);
16994  if (pmarktested(pb)) {
16995  pc = apex(searchtet);
16996  if (pmarktested(pc)) {
16997  // Check if this face intersects [d,e].
16998  interflag = tri_edge_test(pa,pb,pc,pd,pe,NULL,1,types,poss);
16999  if (interflag == 2) {
17000  // They intersect at a single point. Found.
17001  toptet = searchtet;
17002  // The face lies in the interior of R.
17003  // Get the tet (in topnewtets) which lies above R.
17004  ori = orient3d(pa, pb, pc, pd);
17005  if (ori < 0) {
17006  fsymself(toptet);
17007  pa = org(toptet);
17008  pb = dest(toptet);
17009  } else if (ori == 0) {
17010  terminatetetgen(this, 2);
17011  }
17012  // Search the face [b,a,c] in 'botnewtets'.
17013  for (j = 0; j < botnewtets->objects; j++) {
17014  neightet = * (triface *) fastlookup(botnewtets, j);
17015  // Is neightet contains 'b'.
17016  if ((point) neightet.tet[4] == pb) {
17017  neightet.ver = 11;
17018  } else if ((point) neightet.tet[5] == pb) {
17019  neightet.ver = 3;
17020  } else if ((point) neightet.tet[6] == pb) {
17021  neightet.ver = 7;
17022  } else if ((point) neightet.tet[7] == pb) {
17023  neightet.ver = 0;
17024  } else {
17025  continue;
17026  }
17027  // Is the 'neightet' contains edge [b,a].
17028  if (dest(neightet) == pa) {
17029  // 'neightet' is just the edge.
17030  } else if (apex(neightet) == pa) {
17031  eprevesymself(neightet);
17032  } else if (oppo(neightet) == pa) {
17033  esymself(neightet);
17034  enextself(neightet);
17035  } else {
17036  continue;
17037  }
17038  // Is 'neightet' the face [b,a,c].
17039  if (apex(neightet) == pc) {
17040  bottet = neightet;
17041  mflag = true;
17042  break;
17043  }
17044  } // j
17045  } // if (interflag == 2)
17046  } // pc
17047  } // pb
17048  } // pa
17049  } // toptet.ver
17050  } // i
17051 
17052  if (mflag) {
17053  // Found a pair of matched faces in 'toptet' and 'bottet'.
17054  bond(toptet, bottet);
17055  // Both are interior tets.
17056  infect(toptet);
17057  infect(bottet);
17058  // Add this face into search list.
17059  markface(toptet);
17060  midfaces->newindex((void **) &parytet);
17061  *parytet = toptet;
17062  } else {
17063  // No pair of 'toptet' and 'bottet'.
17064  toptet.tet = NULL;
17065  // Randomly split an interior edge of R.
17066  i = randomnation(missingshs->objects - 1);
17067  recentsh = * (face *) fastlookup(missingshs, i);
17068  }
17069 
17070  // Find other middle faces, connect top and bottom tets.
17071  for (i = 0; i < midfaces->objects && mflag; i++) {
17072  // Get a matched middle face [a, b, c]
17073  midface = (triface *) fastlookup(midfaces, i);
17074  // Check the neighbors at the edges of this face.
17075  for (j = 0; j < 3 && mflag; j++) {
17076  toptet = *midface;
17077  bflag = false;
17078  while (1) {
17079  // Go to the next face in the same tet.
17080  esymself(toptet);
17081  pc = apex(toptet);
17082  if (pmarktested(pc)) {
17083  break; // Find a subface.
17084  }
17085  if (pc == dummypoint) {
17086  terminatetetgen(this, 2); // Check this case.
17087  break; // Find a subface.
17088  }
17089  // Go to the adjacent tet.
17090  fsymself(toptet);
17091  // Do we walk outside the cavity?
17092  if (!marktested(toptet)) {
17093  // Yes, the adjacent face is not a middle face.
17094  bflag = true; break;
17095  }
17096  }
17097  if (!bflag) {
17098  if (!facemarked(toptet)) {
17099  fsym(*midface, bottet);
17100  spintet = bottet;
17101  while (1) {
17102  esymself(bottet);
17103  pd = apex(bottet);
17104  if (pd == pc) break; // Face matched.
17105  fsymself(bottet);
17106  if (bottet.tet == spintet.tet) {
17107  // Not found a matched bottom face.
17108  mflag = false;
17109  break;
17110  }
17111  } // while (1)
17112  if (mflag) {
17113  if (marktested(bottet)) {
17114  // Connect two tets together.
17115  bond(toptet, bottet);
17116  // Both are interior tets.
17117  infect(toptet);
17118  infect(bottet);
17119  // Add this face into list.
17120  markface(toptet);
17121  midfaces->newindex((void **) &parytet);
17122  *parytet = toptet;
17123  }
17124  else {
17125  // The 'bottet' is not inside the cavity!
17126  terminatetetgen(this, 2); // Check this case
17127  }
17128  } else { // mflag == false
17129  // Adjust 'toptet' and 'bottet' to be the crossing edges.
17130  fsym(*midface, bottet);
17131  spintet = bottet;
17132  while (1) {
17133  esymself(bottet);
17134  pd = apex(bottet);
17135  if (pmarktested(pd)) {
17136  // assert(pd != pc);
17137  // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
17138  // Adjust 'toptet' and 'bottet' to be the crossing edges.
17139  // Test orient3d(b,c,#,d).
17140  ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
17141  if (ori < 0) {
17142  // Edges [a,d] and [b,c] cross each other.
17143  enextself(toptet); // [b,c]
17144  enextself(bottet); // [a,d]
17145  } else if (ori > 0) {
17146  // Edges [a,c] and [b,d] cross each other.
17147  eprevself(toptet); // [c,a]
17148  eprevself(bottet); // [d,b]
17149  } else {
17150  // b,c,#,and d are coplanar!.
17151  terminatetetgen(this, 2); //assert(0);
17152  }
17153  break; // Not matched
17154  }
17155  fsymself(bottet);
17156  }
17157  } // if (!mflag)
17158  } // if (!facemarked(toptet))
17159  } // if (!bflag)
17160  enextself(*midface);
17161  } // j
17162  } // i
17163 
17164  if (mflag) {
17165  if (b->verbose > 2) {
17166  printf(" Found %ld middle subfaces.\n", midfaces->objects);
17167  }
17168  face oldsh, newsh, casout, casin, neighsh;
17169 
17170  oldsh = * (face *) fastlookup(missingshs, 0);
17171 
17172  // Create new subfaces to fill the region R.
17173  for (i = 0; i < midfaces->objects; i++) {
17174  // Get a matched middle face [a, b, c]
17175  midface = (triface *) fastlookup(midfaces, i);
17176  unmarkface(*midface);
17177  makeshellface(subfaces, &newsh);
17178  setsorg(newsh, org(*midface));
17179  setsdest(newsh, dest(*midface));
17180  setsapex(newsh, apex(*midface));
17181  // The new subface gets its markers from the old one.
17182  setshellmark(newsh, shellmark(oldsh));
17183  if (checkconstraints) {
17184  setareabound(newsh, areabound(oldsh));
17185  }
17186  if (useinsertradius) {
17187  setfacetindex(newsh, getfacetindex(oldsh));
17188  }
17189  // Connect the new subface to adjacent tets.
17190  tsbond(*midface, newsh);
17191  fsym(*midface, neightet);
17192  sesymself(newsh);
17193  tsbond(neightet, newsh);
17194  }
17195 
17196  // Connect new subfaces together and to the bdry of R.
17197  // Delete faked segments.
17198  for (i = 0; i < midfaces->objects; i++) {
17199  // Get a matched middle face [a, b, c]
17200  midface = (triface *) fastlookup(midfaces, i);
17201  for (j = 0; j < 3; j++) {
17202  tspivot(*midface, newsh);
17203  spivot(newsh, casout);
17204  if (casout.sh == NULL) {
17205  // Search its neighbor.
17206  fnext(*midface, searchtet);
17207  while (1) {
17208  // (1) First check if this side is a bdry edge of R.
17209  tsspivot1(searchtet, checkseg);
17210  if (checkseg.sh != NULL) {
17211  // It's a bdry edge of R.
17212  // Get the old subface.
17213  checkseg.shver = 0;
17214  spivot(checkseg, oldsh);
17215  if (sinfected(checkseg)) {
17216  // It's a faked segment. Delete it.
17217  spintet = searchtet;
17218  while (1) {
17219  tssdissolve1(spintet);
17220  fnextself(spintet);
17221  if (spintet.tet == searchtet.tet) break;
17222  }
17223  shellfacedealloc(subsegs, checkseg.sh);
17224  ssdissolve(oldsh);
17225  checkseg.sh = NULL;
17226  }
17227  spivot(oldsh, casout);
17228  if (casout.sh != NULL) {
17229  casin = casout;
17230  if (checkseg.sh != NULL) {
17231  // Make sure that the subface has the right ori at the
17232  // segment.
17233  checkseg.shver = 0;
17234  if (sorg(newsh) != sorg(checkseg)) {
17235  sesymself(newsh);
17236  }
17237  spivot(casin, neighsh);
17238  while (neighsh.sh != oldsh.sh) {
17239  casin = neighsh;
17240  spivot(casin, neighsh);
17241  }
17242  }
17243  sbond1(newsh, casout);
17244  sbond1(casin, newsh);
17245  }
17246  if (checkseg.sh != NULL) {
17247  ssbond(newsh, checkseg);
17248  }
17249  break;
17250  } // if (checkseg.sh != NULL)
17251  // (2) Second check if this side is an interior edge of R.
17252  tspivot(searchtet, neighsh);
17253  if (neighsh.sh != NULL) {
17254  // Found an adjacent subface of newsh (an interior edge).
17255  sbond(newsh, neighsh);
17256  break;
17257  }
17258  fnextself(searchtet);
17259  } // while (1)
17260  } // if (casout.sh == NULL)
17261  enextself(*midface);
17262  } // j
17263  } // i
17264 
17265  // Delete old subfaces.
17266  for (i = 0; i < missingshs->objects; i++) {
17267  parysh = (face *) fastlookup(missingshs, i);
17268  shellfacedealloc(subfaces, parysh->sh);
17269  }
17270  } else {
17271  if (toptet.tet != NULL) {
17272  // Faces at top and bottom are not matched.
17273  // Choose a Steiner point in R.
17274  // Split one of the crossing edges.
17275  pa = org(toptet);
17276  pb = dest(toptet);
17277  pc = org(bottet);
17278  pd = dest(bottet);
17279  // Search an edge in R which is either [a,b] or [c,d].
17280  // Reminder: Subfaces in this list 'missingshs', except the first
17281  // one, represents an interior edge of R.
17282  parysh = NULL; // Avoid a warning in MSVC
17283  for (i = 1; i < missingshs->objects; i++) {
17284  parysh = (face *) fastlookup(missingshs, i);
17285  if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
17286  ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
17287  if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
17288  ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
17289  }
17290  if (i < missingshs->objects) {
17291  // Found. Return it.
17292  recentsh = *parysh;
17293  } else {
17294  terminatetetgen(this, 2); //assert(0);
17295  }
17296  } else {
17297  //terminatetetgen(this, 2); // Report a bug
17298  }
17299  }
17300 
17301  midfaces->restart();
17302  } else {
17303  mflag = true;
17304  }
17305 
17306  // Delete the temp subfaces.
17307  for (j = 0; j < 2; j++) {
17308  cavshells = (j == 0 ? topshells : botshells);
17309  if (cavshells != NULL) {
17310  for (i = 0; i < cavshells->objects; i++) {
17311  parysh = (face *) fastlookup(cavshells, i);
17312  shellfacedealloc(subfaces, parysh->sh);
17313  }
17314  }
17315  }
17316 
17317  topshells->restart();
17318  if (botshells != NULL) {
17319  botshells->restart();
17320  }
17321 
17322  return mflag;
17323 }
17324 
17326 // //
17327 // carvecavity() Delete old tets and outer new tets of the cavity. //
17328 // //
17330 
17331 void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
17332  arraypool *botnewtets)
17333 {
17334  arraypool *newtets;
17335  shellface *sptr, *ssptr;
17336  triface *parytet, *pnewtet, newtet, neightet, spintet;
17337  face checksh, *parysh;
17338  face checkseg, *paryseg;
17339  int t1ver;
17340  int i, j;
17341 
17342  if (b->verbose > 2) {
17343  printf(" Carve cavity: %ld old tets.\n", crosstets->objects);
17344  }
17345 
17346  // First process subfaces and segments which are adjacent to the cavity.
17347  // They must be re-connected to new tets in the cavity.
17348  // Comment: It is possible that some subfaces and segments are completely
17349  // inside the cavity. This can happen even if the cavity is not enlarged.
17350  // Before deleting the old tets, find and queue all interior subfaces
17351  // and segments. They will be recovered later. 2010-05-06.
17352 
17353  // Collect all subfaces and segments which attached to the old tets.
17354  for (i = 0; i < crosstets->objects; i++) {
17355  parytet = (triface *) fastlookup(crosstets, i);
17356  if ((sptr = (shellface*) parytet->tet[9]) != NULL) {
17357  for (j = 0; j < 4; j++) {
17358  if (sptr[j]) {
17359  sdecode(sptr[j], checksh);
17360  if (!sinfected(checksh)) {
17361  sinfect(checksh);
17362  cavetetshlist->newindex((void **) &parysh);
17363  *parysh = checksh;
17364  }
17365  }
17366  } // j
17367  }
17368  if ((ssptr = (shellface*) parytet->tet[8]) != NULL) {
17369  for (j = 0; j < 6; j++) {
17370  if (ssptr[j]) {
17371  sdecode(ssptr[j], checkseg);
17372  // Skip a deleted segment (was a faked segment)
17373  if (checkseg.sh[3] != NULL) {
17374  if (!sinfected(checkseg)) {
17375  sinfect(checkseg);
17376  cavetetseglist->newindex((void **) &paryseg);
17377  *paryseg = checkseg;
17378  }
17379  }
17380  }
17381  } // j
17382  }
17383  } // i
17384 
17385  // Uninfect collected subfaces.
17386  for (i = 0; i < cavetetshlist->objects; i++) {
17387  parysh = (face *) fastlookup(cavetetshlist, i);
17388  suninfect(*parysh);
17389  }
17390  // Uninfect collected segments.
17391  for (i = 0; i < cavetetseglist->objects; i++) {
17392  paryseg = (face *) fastlookup(cavetetseglist, i);
17393  suninfect(*paryseg);
17394  }
17395 
17396  // Connect subfaces to new tets.
17397  for (i = 0; i < cavetetshlist->objects; i++) {
17398  parysh = (face *) fastlookup(cavetetshlist, i);
17399  // Get an adjacent tet at this subface.
17400  stpivot(*parysh, neightet);
17401  // Does this tet lie inside the cavity.
17402  if (infected(neightet)) {
17403  // Yes. Get the other adjacent tet at this subface.
17404  sesymself(*parysh);
17405  stpivot(*parysh, neightet);
17406  // Does this tet lie inside the cavity.
17407  if (infected(neightet)) {
17408  checksh = *parysh;
17409  stdissolve(checksh);
17410  caveencshlist->newindex((void **) &parysh);
17411  *parysh = checksh;
17412  }
17413  }
17414  if (!infected(neightet)) {
17415  // Found an outside tet. Re-connect this subface to a new tet.
17416  fsym(neightet, newtet);
17417  sesymself(*parysh);
17418  tsbond(newtet, *parysh);
17419  }
17420  } // i
17421 
17422 
17423  for (i = 0; i < cavetetseglist->objects; i++) {
17424  checkseg = * (face *) fastlookup(cavetetseglist, i);
17425  // Check if the segment is inside the cavity.
17426  sstpivot1(checkseg, neightet);
17427  spintet = neightet;
17428  while (1) {
17429  if (!infected(spintet)) {
17430  // This segment is on the boundary of the cavity.
17431  break;
17432  }
17433  fnextself(spintet);
17434  if (spintet.tet == neightet.tet) {
17435  sstdissolve1(checkseg);
17436  caveencseglist->newindex((void **) &paryseg);
17437  *paryseg = checkseg;
17438  break;
17439  }
17440  }
17441  if (!infected(spintet)) {
17442  // A boundary segment. Connect this segment to the new tets.
17443  sstbond1(checkseg, spintet);
17444  neightet = spintet;
17445  while (1) {
17446  tssbond1(spintet, checkseg);
17447  fnextself(spintet);
17448  if (spintet.tet == neightet.tet) break;
17449  }
17450  }
17451  } // i
17452 
17453 
17454  cavetetshlist->restart();
17455  cavetetseglist->restart();
17456 
17457  // Delete the old tets in cavity.
17458  for (i = 0; i < crosstets->objects; i++) {
17459  parytet = (triface *) fastlookup(crosstets, i);
17460  if (ishulltet(*parytet)) {
17461  hullsize--;
17462  }
17463  tetrahedrondealloc(parytet->tet);
17464  }
17465 
17466  crosstets->restart(); // crosstets will be re-used.
17467 
17468  // Collect new tets in cavity. Some new tets have already been found
17469  // (and infected) in the fillcavity(). We first collect them.
17470  for (j = 0; j < 2; j++) {
17471  newtets = (j == 0 ? topnewtets : botnewtets);
17472  if (newtets != NULL) {
17473  for (i = 0; i < newtets->objects; i++) {
17474  parytet = (triface *) fastlookup(newtets, i);
17475  if (infected(*parytet)) {
17476  crosstets->newindex((void **) &pnewtet);
17477  *pnewtet = *parytet;
17478  }
17479  } // i
17480  }
17481  } // j
17482 
17483  // Now we collect all new tets in cavity.
17484  for (i = 0; i < crosstets->objects; i++) {
17485  parytet = (triface *) fastlookup(crosstets, i);
17486  for (j = 0; j < 4; j++) {
17487  decode(parytet->tet[j], neightet);
17488  if (marktested(neightet)) { // Is it a new tet?
17489  if (!infected(neightet)) {
17490  // Find an interior tet.
17491  //assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
17492  infect(neightet);
17493  crosstets->newindex((void **) &pnewtet);
17494  *pnewtet = neightet;
17495  }
17496  }
17497  } // j
17498  } // i
17499 
17500  parytet = (triface *) fastlookup(crosstets, 0);
17501  recenttet = *parytet; // Remember a live handle.
17502 
17503  // Delete outer new tets.
17504  for (j = 0; j < 2; j++) {
17505  newtets = (j == 0 ? topnewtets : botnewtets);
17506  if (newtets != NULL) {
17507  for (i = 0; i < newtets->objects; i++) {
17508  parytet = (triface *) fastlookup(newtets, i);
17509  if (infected(*parytet)) {
17510  // This is an interior tet.
17511  uninfect(*parytet);
17512  unmarktest(*parytet);
17513  if (ishulltet(*parytet)) {
17514  hullsize++;
17515  }
17516  } else {
17517  // An outer tet. Delete it.
17518  tetrahedrondealloc(parytet->tet);
17519  }
17520  }
17521  }
17522  }
17523 
17524  crosstets->restart();
17525  topnewtets->restart();
17526  if (botnewtets != NULL) {
17527  botnewtets->restart();
17528  }
17529 }
17530 
17532 // //
17533 // restorecavity() Reconnect old tets and delete new tets of the cavity. //
17534 // //
17536 
17537 void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
17538  arraypool *botnewtets, arraypool *missingshbds)
17539 {
17540  triface *parytet, neightet, spintet;
17541  face *parysh;
17542  face checkseg;
17543  point *ppt;
17544  int t1ver;
17545  int i, j;
17546 
17547  // Reconnect crossing tets to cavity boundary.
17548  for (i = 0; i < crosstets->objects; i++) {
17549  parytet = (triface *) fastlookup(crosstets, i);
17550  parytet->ver = 0;
17551  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
17552  fsym(*parytet, neightet);
17553  if (!infected(neightet)) {
17554  // Restore the old connections of tets.
17555  bond(*parytet, neightet);
17556  }
17557  }
17558  // Update the point-to-tet map.
17559  parytet->ver = 0;
17560  ppt = (point *) &(parytet->tet[4]);
17561  for (j = 0; j < 4; j++) {
17562  setpoint2tet(ppt[j], encode(*parytet));
17563  }
17564  }
17565 
17566  // Uninfect all crossing tets.
17567  for (i = 0; i < crosstets->objects; i++) {
17568  parytet = (triface *) fastlookup(crosstets, i);
17569  uninfect(*parytet);
17570  }
17571 
17572  // Remember a live handle.
17573  if (crosstets->objects > 0) {
17574  recenttet = * (triface *) fastlookup(crosstets, 0);
17575  }
17576 
17577  // Delete faked segments.
17578  for (i = 0; i < missingshbds->objects; i++) {
17579  parysh = (face *) fastlookup(missingshbds, i);
17580  sspivot(*parysh, checkseg);
17581  if (checkseg.sh[3] != NULL) {
17582  if (sinfected(checkseg)) {
17583  // It's a faked segment. Delete it.
17584  sstpivot1(checkseg, neightet);
17585  spintet = neightet;
17586  while (1) {
17587  tssdissolve1(spintet);
17588  fnextself(spintet);
17589  if (spintet.tet == neightet.tet) break;
17590  }
17591  shellfacedealloc(subsegs, checkseg.sh);
17592  ssdissolve(*parysh);
17593  //checkseg.sh = NULL;
17594  }
17595  }
17596  } // i
17597 
17598  // Delete new tets.
17599  for (i = 0; i < topnewtets->objects; i++) {
17600  parytet = (triface *) fastlookup(topnewtets, i);
17601  tetrahedrondealloc(parytet->tet);
17602  }
17603 
17604  if (botnewtets != NULL) {
17605  for (i = 0; i < botnewtets->objects; i++) {
17606  parytet = (triface *) fastlookup(botnewtets, i);
17607  tetrahedrondealloc(parytet->tet);
17608  }
17609  }
17610 
17611  crosstets->restart();
17612  topnewtets->restart();
17613  if (botnewtets != NULL) {
17614  botnewtets->restart();
17615  }
17616 }
17617 
17619 // //
17620 // flipcertify() Insert a crossing face into priority queue. //
17621 // //
17622 // A crossing face of a facet must have at least one top and one bottom ver- //
17623 // tex of the facet. //
17624 // //
17626 
17627 void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
17628  point plane_pb, point plane_pc)
17629 {
17630  badface *parybf, *prevbf, *nextbf;
17631  triface neightet;
17632  face checksh;
17633  point p[5];
17634  REAL w[5];
17635  REAL insph, ori4;
17636  int topi, boti;
17637  int i;
17638 
17639  // Compute the flip time \tau.
17640  fsym(*chkface, neightet);
17641 
17642  p[0] = org(*chkface);
17643  p[1] = dest(*chkface);
17644  p[2] = apex(*chkface);
17645  p[3] = oppo(*chkface);
17646  p[4] = oppo(neightet);
17647 
17648  // Check if the face is a crossing face.
17649  topi = boti = 0;
17650  for (i = 0; i < 3; i++) {
17651  if (pmarktest2ed(p[i])) topi++;
17652  if (pmarktest3ed(p[i])) boti++;
17653  }
17654  if ((topi == 0) || (boti == 0)) {
17655  // It is not a crossing face.
17656  // return;
17657  for (i = 3; i < 5; i++) {
17658  if (pmarktest2ed(p[i])) topi++;
17659  if (pmarktest3ed(p[i])) boti++;
17660  }
17661  if ((topi == 0) || (boti == 0)) {
17662  // The two tets sharing at this face are on one side of the facet.
17663  // Check if this face is locally Delaunay (due to rounding error).
17664  if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
17665  // Do not check it if it is a subface.
17666  tspivot(*chkface, checksh);
17667  if (checksh.sh == NULL) {
17668  insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
17669  if (insph > 0) {
17670  // Add the face into queue.
17671  if (b->verbose > 2) {
17672  printf(" A locally non-Delanay face (%d, %d, %d)-%d,%d\n",
17673  pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
17674  pointmark(p[3]), pointmark(p[4]));
17675  }
17676  parybf = (badface *) flippool->alloc();
17677  parybf->key = 0.; // tau = 0, do immediately.
17678  parybf->tt = *chkface;
17679  parybf->forg = p[0];
17680  parybf->fdest = p[1];
17681  parybf->fapex = p[2];
17682  parybf->foppo = p[3];
17683  parybf->noppo = p[4];
17684  // Add it at the top of the priority queue.
17685  if (*pqueue == NULL) {
17686  *pqueue = parybf;
17687  parybf->nextitem = NULL;
17688  } else {
17689  parybf->nextitem = *pqueue;
17690  *pqueue = parybf;
17691  }
17692  } // if (insph > 0)
17693  } // if (checksh.sh == NULL)
17694  }
17695  }
17696  return; // Test: omit this face.
17697  }
17698 
17699  // Decide the "height" for each point.
17700  for (i = 0; i < 5; i++) {
17701  if (pmarktest2ed(p[i])) {
17702  // A top point has a positive weight.
17703  w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);
17704  if (w[i] < 0) w[i] = -w[i];
17705  } else {
17706  w[i] = 0;
17707  }
17708  }
17709 
17710  insph = insphere(p[1], p[0], p[2], p[3], p[4]);
17711  ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
17712  if (ori4 > 0) {
17713  // Add the face into queue.
17714  if (b->verbose > 2) {
17715  printf(" Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
17716  pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
17717  }
17718 
17719  parybf = (badface *) flippool->alloc();
17720 
17721  parybf->key = -insph / ori4;
17722  parybf->tt = *chkface;
17723  parybf->forg = p[0];
17724  parybf->fdest = p[1];
17725  parybf->fapex = p[2];
17726  parybf->foppo = p[3];
17727  parybf->noppo = p[4];
17728 
17729  // Push the face into priority queue.
17730  //pq.push(bface);
17731  if (*pqueue == NULL) {
17732  *pqueue = parybf;
17733  parybf->nextitem = NULL;
17734  } else {
17735  // Search an item whose key is larger or equal to current key.
17736  prevbf = NULL;
17737  nextbf = *pqueue;
17738  //if (!b->flipinsert_random) { // Default use a priority queue.
17739  // Insert the item into priority queue.
17740  while (nextbf != NULL) {
17741  if (nextbf->key < parybf->key) {
17742  prevbf = nextbf;
17743  nextbf = nextbf->nextitem;
17744  } else {
17745  break;
17746  }
17747  }
17748  //} // if (!b->flipinsert_random)
17749  // Insert the new item between prev and next items.
17750  if (prevbf == NULL) {
17751  *pqueue = parybf;
17752  } else {
17753  prevbf->nextitem = parybf;
17754  }
17755  parybf->nextitem = nextbf;
17756  }
17757  } else if (ori4 == 0) {
17758 
17759  }
17760 }
17761 
17763 // //
17764 // flipinsertfacet() Insert a facet into a CDT by flips. //
17765 // //
17766 // The algorithm is described in Shewchuk's paper "Updating and Constructing //
17767 // Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
17768 // Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003. //
17769 // //
17770 // 'crosstets' contains the set of crossing tetrahedra (infected) of the //
17771 // facet. 'toppoints' and 'botpoints' are points lies above and below the //
17772 // facet, not on the facet. //
17773 // //
17775 
17776 void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
17777  arraypool *botpoints, arraypool *midpoints)
17778 {
17779  arraypool *crossfaces, *bfacearray;
17780  triface fliptets[6], baktets[2], fliptet, newface;
17781  triface neightet, *parytet;
17782  badface *pqueue;
17783  badface *popbf, bface;
17784  point plane_pa, plane_pb, plane_pc;
17785  point p1, p2, pd, pe;
17786  point *parypt;
17787  flipconstraints fc;
17788  REAL ori[3];
17789  int convcount, copcount;
17790  int flipflag, fcount;
17791  int n, i;
17792  long f23count, f32count, f44count;
17793  long totalfcount;
17794 
17795  f23count = flip23count;
17796  f32count = flip32count;
17797  f44count = flip44count;
17798 
17799  // Get three affinely independent vertices in the missing region R.
17800  calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
17801 
17802  // Mark top and bottom points. Do not mark midpoints.
17803  for (i = 0; i < toppoints->objects; i++) {
17804  parypt = (point *) fastlookup(toppoints, i);
17805  if (!pmarktested(*parypt)) {
17806  pmarktest2(*parypt);
17807  }
17808  }
17809  for (i = 0; i < botpoints->objects; i++) {
17810  parypt = (point *) fastlookup(botpoints, i);
17811  if (!pmarktested(*parypt)) {
17812  pmarktest3(*parypt);
17813  }
17814  }
17815 
17816  // Collect crossing faces.
17817  crossfaces = cavetetlist; // Re-use array 'cavetetlist'.
17818 
17819  // Each crossing face contains at least one bottom vertex and
17820  // one top vertex.
17821  for (i = 0; i < crosstets->objects; i++) {
17822  parytet = (triface *) fastlookup(crosstets, i);
17823  fliptet = *parytet;
17824  for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
17825  fsym(fliptet, neightet);
17826  if (infected(neightet)) { // It is an interior face.
17827  if (!marktested(neightet)) { // It is an unprocessed face.
17828  crossfaces->newindex((void **) &parytet);
17829  *parytet = fliptet;
17830  }
17831  }
17832  }
17833  marktest(fliptet);
17834  }
17835 
17836  if (b->verbose > 1) {
17837  printf(" Found %ld crossing faces.\n", crossfaces->objects);
17838  }
17839 
17840  for (i = 0; i < crosstets->objects; i++) {
17841  parytet = (triface *) fastlookup(crosstets, i);
17842  unmarktest(*parytet);
17843  uninfect(*parytet);
17844  }
17845 
17846  // Initialize the priority queue.
17847  pqueue = NULL;
17848 
17849  for (i = 0; i < crossfaces->objects; i++) {
17850  parytet = (triface *) fastlookup(crossfaces, i);
17851  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17852  }
17853  crossfaces->restart();
17854 
17855  // The list for temporarily storing unflipable faces.
17856  bfacearray = new arraypool(sizeof(triface), 4);
17857 
17858 
17859  fcount = 0; // Count the number of flips.
17860 
17861  // Flip insert the facet.
17862  while (pqueue != NULL) {
17863 
17864  // Pop a face from the priority queue.
17865  popbf = pqueue;
17866  bface = *popbf;
17867  // Update the queue.
17868  pqueue = pqueue->nextitem;
17869  // Delete the popped item from the pool.
17870  flippool->dealloc((void *) popbf);
17871 
17872  if (!isdeadtet(bface.tt)) {
17873  if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
17874  (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
17875  // It is still a crossing face of R.
17876  fliptet = bface.tt;
17877  fsym(fliptet, neightet);
17878  if (oppo(neightet) == bface.noppo) {
17879  pd = oppo(fliptet);
17880  pe = oppo(neightet);
17881 
17882  if (b->verbose > 2) {
17883  printf(" Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17884  pointmark(bface.forg), pointmark(bface.fdest),
17885  pointmark(bface.fapex), pointmark(bface.foppo),
17886  pointmark(bface.noppo), bface.key);
17887  }
17888  flipflag = 0;
17889 
17890  // Check for which type of flip can we do.
17891  convcount = 3;
17892  copcount = 0;
17893  for (i = 0; i < 3; i++) {
17894  p1 = org(fliptet);
17895  p2 = dest(fliptet);
17896  ori[i] = orient3d(p1, p2, pd, pe);
17897  if (ori[i] < 0) {
17898  convcount--;
17899  //break;
17900  } else if (ori[i] == 0) {
17901  convcount--; // Possible 4-to-4 flip.
17902  copcount++;
17903  //break;
17904  }
17905  enextself(fliptet);
17906  }
17907 
17908  if (convcount == 3) {
17909  // A 2-to-3 flip is found.
17910  fliptets[0] = fliptet; // abcd, d may be the new vertex.
17911  fliptets[1] = neightet; // bace.
17912  flip23(fliptets, 1, &fc);
17913  // Put the link faces into check list.
17914  for (i = 0; i < 3; i++) {
17915  eprevesym(fliptets[i], newface);
17916  crossfaces->newindex((void **) &parytet);
17917  *parytet = newface;
17918  }
17919  for (i = 0; i < 3; i++) {
17920  enextesym(fliptets[i], newface);
17921  crossfaces->newindex((void **) &parytet);
17922  *parytet = newface;
17923  }
17924  flipflag = 1;
17925  } else if (convcount == 2) {
17926  //if (copcount <= 1) {
17927  // A 3-to-2 or 4-to-4 may be possible.
17928  // Get the edge which is locally non-convex or flat.
17929  for (i = 0; i < 3; i++) {
17930  if (ori[i] <= 0) break;
17931  enextself(fliptet);
17932  }
17933 
17934  // Collect tets sharing at this edge.
17935  esym(fliptet, fliptets[0]); // [b,a,d,c]
17936  n = 0;
17937  do {
17938  p1 = apex(fliptets[n]);
17939  if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
17940  // This apex is not on the cavity. Hence the face does not
17941  // lie inside the cavity. Do not flip this edge.
17942  n = 1000; break;
17943  }
17944  fnext(fliptets[n], fliptets[n + 1]);
17945  n++;
17946  } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
17947 
17948  if (n == 3) {
17949  // Found a 3-to-2 flip.
17950  flip32(fliptets, 1, &fc);
17951  // Put the link faces into check list.
17952  for (i = 0; i < 3; i++) {
17953  esym(fliptets[0], newface);
17954  crossfaces->newindex((void **) &parytet);
17955  *parytet = newface;
17956  enextself(fliptets[0]);
17957  }
17958  for (i = 0; i < 3; i++) {
17959  esym(fliptets[1], newface);
17960  crossfaces->newindex((void **) &parytet);
17961  *parytet = newface;
17962  enextself(fliptets[1]);
17963  }
17964  flipflag = 1;
17965  } else if (n == 4) {
17966  if (copcount == 1) {
17967  // Found a 4-to-4 flip.
17968  // Let the six vertices are: a,b,c,d,e,f, where
17969  // fliptets[0] = [b,a,d,c]
17970  // [1] = [b,a,c,e]
17971  // [2] = [b,a,e,f]
17972  // [3] = [b,a,f,d]
17973  // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
17974  // is created.
17975  // First do a 2-to-3 flip.
17976  // Comment: This flip temporarily creates a degenerated
17977  // tet (whose volume is zero). It will be removed by the
17978  // followed 3-to-2 flip.
17979  fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
17980  // fliptets[1]; // = [b,a,c,e].
17981  baktets[0] = fliptets[2]; // = [b,a,e,f]
17982  baktets[1] = fliptets[3]; // = [b,a,f,d]
17983  // The flip may involve hull tets.
17984  flip23(fliptets, 1, &fc);
17985  // Put the "outer" link faces into check list.
17986  // fliptets[0] = [e,d,a,b] => will be flipped, so
17987  // [a,b,d] and [a,b,e] are not "outer" link faces.
17988  for (i = 1; i < 3; i++) {
17989  eprevesym(fliptets[i], newface);
17990  crossfaces->newindex((void **) &parytet);
17991  *parytet = newface;
17992  }
17993  for (i = 1; i < 3; i++) {
17994  enextesym(fliptets[i], newface);
17995  crossfaces->newindex((void **) &parytet);
17996  *parytet = newface;
17997  }
17998  // Then do a 3-to-2 flip.
17999  enextesymself(fliptets[0]); // fliptets[0] is [e,d,a,b].
18000  eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
18001  fliptets[1] = baktets[0]; // = [b,a,e,f]
18002  fliptets[2] = baktets[1]; // = [b,a,f,d]
18003  flip32(fliptets, 1, &fc);
18004  // Put the "outer" link faces into check list.
18005  // fliptets[0] = [d,e,f,a]
18006  // fliptets[1] = [e,d,f,b]
18007  // Faces [a,b,d] and [a,b,e] are not "outer" link faces.
18008  enextself(fliptets[0]);
18009  for (i = 1; i < 3; i++) {
18010  esym(fliptets[0], newface);
18011  crossfaces->newindex((void **) &parytet);
18012  *parytet = newface;
18013  enextself(fliptets[0]);
18014  }
18015  enextself(fliptets[1]);
18016  for (i = 1; i < 3; i++) {
18017  esym(fliptets[1], newface);
18018  crossfaces->newindex((void **) &parytet);
18019  *parytet = newface;
18020  enextself(fliptets[1]);
18021  }
18022  flip23count--;
18023  flip32count--;
18024  flip44count++;
18025  flipflag = 1;
18026  }
18027  }
18028  } else {
18029  // There are more than 1 non-convex or coplanar cases.
18030  flipflag = -1; // Ignore this face.
18031  if (b->verbose > 2) {
18032  printf(" Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
18033  pointmark(bface.forg), pointmark(bface.fdest),
18034  pointmark(bface.fapex), pointmark(bface.foppo),
18035  pointmark(bface.noppo), bface.key);
18036  }
18037  } // if (convcount == 1)
18038 
18039  if (flipflag == 1) {
18040  // Update the priority queue.
18041  for (i = 0; i < crossfaces->objects; i++) {
18042  parytet = (triface *) fastlookup(crossfaces, i);
18043  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
18044  }
18045  crossfaces->restart();
18046  if (1) { // if (!b->flipinsert_random) {
18047  // Insert all queued unflipped faces.
18048  for (i = 0; i < bfacearray->objects; i++) {
18049  parytet = (triface *) fastlookup(bfacearray, i);
18050  // This face may be changed.
18051  if (!isdeadtet(*parytet)) {
18052  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
18053  }
18054  }
18055  bfacearray->restart();
18056  }
18057  fcount++;
18058  } else if (flipflag == 0) {
18059  // Queue an unflippable face. To process it later.
18060  bfacearray->newindex((void **) &parytet);
18061  *parytet = fliptet;
18062  }
18063  } // if (pe == bface.noppo)
18064  } // if ((pa == bface.forg) && ...)
18065  } // if (bface.tt != NULL)
18066 
18067  } // while (pqueue != NULL)
18068 
18069  if (bfacearray->objects > 0) {
18070  if (fcount == 0) {
18071  printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
18072  terminatetetgen(this, 2); //assert(0);
18073  }
18074  }
18075 
18076  delete bfacearray;
18077 
18078  // Un-mark top and bottom points.
18079  for (i = 0; i < toppoints->objects; i++) {
18080  parypt = (point *) fastlookup(toppoints, i);
18081  punmarktest2(*parypt);
18082  }
18083  for (i = 0; i < botpoints->objects; i++) {
18084  parypt = (point *) fastlookup(botpoints, i);
18085  punmarktest3(*parypt);
18086  }
18087 
18088  f23count = flip23count - f23count;
18089  f32count = flip32count - f32count;
18090  f44count = flip44count - f44count;
18091  totalfcount = f23count + f32count + f44count;
18092  if (b->verbose > 2) {
18093  printf(" Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
18094  totalfcount, f23count, f32count, f44count);
18095  }
18096 }
18097 
18099 // //
18100 // insertpoint_cdt() Insert a new point into a CDT. //
18101 // //
18103 
18104 int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh,
18105  face *splitseg, insertvertexflags *ivf,
18106  arraypool *cavpoints, arraypool *cavfaces,
18107  arraypool *cavshells, arraypool *newtets,
18108  arraypool *crosstets, arraypool *misfaces)
18109 {
18110  triface neightet, *parytet;
18111  face checksh, *parysh, *parysh1;
18112  face *paryseg, *paryseg1;
18113  point *parypt;
18114  int t1ver;
18115  int i;
18116 
18117  if (b->verbose > 2) {
18118  printf(" Insert point %d into CDT\n", pointmark(newpt));
18119  }
18120 
18121  if (!insertpoint(newpt, searchtet, NULL, NULL, ivf)) {
18122  // Point is not inserted. Check ivf->iloc for reason.
18123  return 0;
18124  }
18125 
18126 
18127  for (i = 0; i < cavetetvertlist->objects; i++) {
18128  cavpoints->newindex((void **) &parypt);
18129  *parypt = * (point *) fastlookup(cavetetvertlist, i);
18130  }
18131  // Add the new point into the point list.
18132  cavpoints->newindex((void **) &parypt);
18133  *parypt = newpt;
18134 
18135  for (i = 0; i < cavebdrylist->objects; i++) {
18136  cavfaces->newindex((void **) &parytet);
18137  *parytet = * (triface *) fastlookup(cavebdrylist, i);
18138  }
18139 
18140  for (i = 0; i < caveoldtetlist->objects; i++) {
18141  crosstets->newindex((void **) &parytet);
18142  *parytet = * (triface *) fastlookup(caveoldtetlist, i);
18143  }
18144 
18145  cavetetvertlist->restart();
18146  cavebdrylist->restart();
18147  caveoldtetlist->restart();
18148 
18149  // Insert the point using the cavity algorithm.
18150  delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets,
18151  misfaces);
18152  fillcavity(cavshells, NULL, NULL, NULL, NULL, NULL, NULL);
18153  carvecavity(crosstets, newtets, NULL);
18154 
18155  if ((splitsh != NULL) || (splitseg != NULL)) {
18156  // Insert the point into the surface mesh.
18157  sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
18158 
18159  // Put all new subfaces into stack.
18160  for (i = 0; i < caveshbdlist->objects; i++) {
18161  // Get an old subface at edge [a, b].
18162  parysh = (face *) fastlookup(caveshbdlist, i);
18163  spivot(*parysh, checksh); // The new subface [a, b, p].
18164  // Do not recover a deleted new face (degenerated).
18165  if (checksh.sh[3] != NULL) {
18166  subfacstack->newindex((void **) &parysh);
18167  *parysh = checksh;
18168  }
18169  }
18170 
18171  if (splitseg != NULL) {
18172  // Queue two new subsegments in C(p) for recovery.
18173  for (i = 0; i < cavesegshlist->objects; i++) {
18174  paryseg = (face *) fastlookup(cavesegshlist, i);
18175  subsegstack->newindex((void **) &paryseg1);
18176  *paryseg1 = *paryseg;
18177  }
18178  } // if (splitseg != NULL)
18179 
18180  // Delete the old subfaces in sC(p).
18181  for (i = 0; i < caveshlist->objects; i++) {
18182  parysh = (face *) fastlookup(caveshlist, i);
18183  if (checksubfaceflag) {
18184  // It is possible that this subface still connects to adjacent
18185  // tets which are not in C(p). If so, clear connections in the
18186  // adjacent tets at this subface.
18187  stpivot(*parysh, neightet);
18188  if (neightet.tet != NULL) {
18189  if (neightet.tet[4] != NULL) {
18190  // Found an adjacent tet. It must be not in C(p).
18191  tsdissolve(neightet);
18192  fsymself(neightet);
18193  tsdissolve(neightet);
18194  }
18195  }
18196  }
18197  shellfacedealloc(subfaces, parysh->sh);
18198  }
18199  if (splitseg != NULL) {
18200  // Delete the old segment in sC(p).
18201  shellfacedealloc(subsegs, splitseg->sh);
18202  }
18203 
18204  // Clear working lists.
18205  caveshlist->restart();
18206  caveshbdlist->restart();
18207  cavesegshlist->restart();
18208  } // if ((splitsh != NULL) || (splitseg != NULL))
18209 
18210  // Put all interior subfaces into stack for recovery.
18211  // They were collected in carvecavity().
18212  // Note: Some collected subfaces may be deleted by sinsertvertex().
18213  for (i = 0; i < caveencshlist->objects; i++) {
18214  parysh = (face *) fastlookup(caveencshlist, i);
18215  if (parysh->sh[3] != NULL) {
18216  subfacstack->newindex((void **) &parysh1);
18217  *parysh1 = *parysh;
18218  }
18219  }
18220 
18221  // Put all interior segments into stack for recovery.
18222  // They were collected in carvecavity().
18223  // Note: Some collected segments may be deleted by sinsertvertex().
18224  for (i = 0; i < caveencseglist->objects; i++) {
18225  paryseg = (face *) fastlookup(caveencseglist, i);
18226  if (paryseg->sh[3] != NULL) {
18227  subsegstack->newindex((void **) &paryseg1);
18228  *paryseg1 = *paryseg;
18229  }
18230  }
18231 
18232  caveencshlist->restart();
18233  caveencseglist->restart();
18234 
18235  return 1;
18236 }
18237 
18239 // //
18240 // refineregion() Refine a missing region by inserting points. //
18241 // //
18242 // 'splitsh' represents an edge of the facet to be split. It must be not a //
18243 // segment.
18244 // //
18245 // Assumption: The current mesh is a CDT and is convex. //
18246 // //
18248 
18249 void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints,
18250  arraypool *cavfaces, arraypool *cavshells,
18251  arraypool *newtets, arraypool *crosstets,
18252  arraypool *misfaces)
18253 {
18254  triface searchtet, spintet;
18255  face splitseg, *paryseg;
18256  point steinpt, pa, pb, refpt;
18257  insertvertexflags ivf;
18258  enum interresult dir;
18259  long baknum = points->items;
18260  int t1ver;
18261  int i;
18262 
18263  // Do not split a segment.
18264  for (i = 0; i < 3; i++) {
18265  sspivot(splitsh, splitseg);
18266  if (splitseg.sh == NULL) break;
18267  senextself(splitsh);
18268  }
18269 
18270  if (b->verbose > 2) {
18271  printf(" Refining region at edge (%d, %d, %d).\n",
18272  pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
18273  pointmark(sapex(splitsh)));
18274  }
18275 
18276  // Add the Steiner point at the barycenter of the face.
18277  pa = sorg(splitsh);
18278  pb = sdest(splitsh);
18279  // Create a new point.
18280  makepoint(&steinpt, FREEFACETVERTEX);
18281  for (i = 0; i < 3; i++) {
18282  steinpt[i] = 0.5 * (pa[i] + pb[i]);
18283  }
18284 
18285  ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
18286  ivf.cdtflag = 1; // Only create the initial cavity.
18287  ivf.sloc = (int) ONEDGE;
18288  ivf.sbowywat = 1;
18289  ivf.assignmeshsize = b->metric;
18290  ivf.smlenflag = useinsertradius; // Return the closet mesh vertex.
18291 
18292  point2tetorg(pa, searchtet); // Start location from it.
18293  ivf.iloc = (int) OUTSIDE;
18294 
18295  ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
18296  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, NULL, &ivf, cavpoints,
18297  cavfaces, cavshells, newtets, crosstets, misfaces)) {
18298  if (ivf.iloc == (int) ENCSEGMENT) {
18299  pointdealloc(steinpt);
18300  // Split an encroached segment.
18301  i = randomnation(encseglist->objects);
18302  paryseg = (face *) fastlookup(encseglist, i);
18303  splitseg = *paryseg;
18304  encseglist->restart();
18305 
18306  // Split the segment.
18307  pa = sorg(splitseg);
18308  pb = sdest(splitseg);
18309  // Create a new point.
18310  makepoint(&steinpt, FREESEGVERTEX);
18311  for (i = 0; i < 3; i++) {
18312  steinpt[i] = 0.5 * (pa[i] + pb[i]);
18313  }
18314  point2tetorg(pa, searchtet);
18315  ivf.iloc = (int) OUTSIDE;
18316  ivf.rejflag = 0;
18317  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
18318  cavpoints, cavfaces, cavshells, newtets,
18319  crosstets, misfaces)) {
18320  terminatetetgen(this, 2);
18321  }
18322  if (useinsertradius) {
18323  save_segmentpoint_insradius(steinpt, ivf.parentpt, ivf.smlen);
18324  }
18325  st_segref_count++;
18326  if (steinerleft > 0) steinerleft--;
18327  } else {
18328  terminatetetgen(this, 2); // assert(0);
18329  }
18330  } else {
18331  if (useinsertradius) {
18332  save_facetpoint_insradius(steinpt, ivf.parentpt, ivf.smlen);
18333  }
18334  st_facref_count++;
18335  if (steinerleft > 0) steinerleft--;
18336  }
18337 
18338  while (subsegstack->objects > 0l) {
18339  // seglist is used as a stack.
18340  subsegstack->objects--;
18341  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
18342  splitseg = *paryseg;
18343 
18344  // Check if this segment has been recovered.
18345  sstpivot1(splitseg, searchtet);
18346  if (searchtet.tet != NULL) continue;
18347 
18348  // Search the segment.
18349  dir = scoutsegment(sorg(splitseg), sdest(splitseg), &splitseg, &searchtet,
18350  &refpt, NULL);
18351  if (dir == SHAREEDGE) {
18352  // Found this segment, insert it.
18353  // Let the segment remember an adjacent tet.
18354  sstbond1(splitseg, searchtet);
18355  // Bond the segment to all tets containing it.
18356  spintet = searchtet;
18357  do {
18358  tssbond1(spintet, splitseg);
18359  fnextself(spintet);
18360  } while (spintet.tet != searchtet.tet);
18361  } else {
18362  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
18363  // Split the segment.
18364  makepoint(&steinpt, FREESEGVERTEX);
18365  getsteinerptonsegment(&splitseg, refpt, steinpt);
18366  ivf.iloc = (int) OUTSIDE;
18367  ivf.rejflag = 0;
18368  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
18369  cavpoints, cavfaces, cavshells, newtets,
18370  crosstets, misfaces)) {
18371  terminatetetgen(this, 2);
18372  }
18373  if (useinsertradius) {
18374  save_segmentpoint_insradius(steinpt, ivf.parentpt, ivf.smlen);
18375  }
18376  st_segref_count++;
18377  if (steinerleft > 0) steinerleft--;
18378  } else {
18379  terminatetetgen(this, 2);
18380  }
18381  }
18382  } // while
18383 
18384  if (b->verbose > 2) {
18385  printf(" Added %ld Steiner points.\n", points->items - baknum);
18386  }
18387 }
18388 
18390 // //
18391 // constrainedfacets() Recover constrained facets in a CDT. //
18392 // //
18393 // All unrecovered subfaces are queued in 'subfacestack'. //
18394 // //
18396 
18397 void tetgenmesh::constrainedfacets()
18398 {
18399  arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
18400  arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
18401  arraypool *tg_topshells, *tg_botshells, *tg_facfaces;
18402  arraypool *tg_toppoints, *tg_botpoints;
18403  arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
18404  triface searchtet, neightet, crossedge;
18405  face searchsh, *parysh, *parysh1;
18406  face *paryseg;
18407  point *parypt;
18408  enum interresult dir;
18409  int facetcount;
18410  int success;
18411  int t1ver;
18412  int i, j;
18413 
18414  // Initialize arrays.
18415  tg_crosstets = new arraypool(sizeof(triface), 10);
18416  tg_topnewtets = new arraypool(sizeof(triface), 10);
18417  tg_botnewtets = new arraypool(sizeof(triface), 10);
18418  tg_topfaces = new arraypool(sizeof(triface), 10);
18419  tg_botfaces = new arraypool(sizeof(triface), 10);
18420  tg_midfaces = new arraypool(sizeof(triface), 10);
18421  tg_toppoints = new arraypool(sizeof(point), 8);
18422  tg_botpoints = new arraypool(sizeof(point), 8);
18423  tg_facfaces = new arraypool(sizeof(face), 10);
18424  tg_topshells = new arraypool(sizeof(face), 10);
18425  tg_botshells = new arraypool(sizeof(face), 10);
18426  tg_missingshs = new arraypool(sizeof(face), 10);
18427  tg_missingshbds = new arraypool(sizeof(face), 10);
18428  tg_missingshverts = new arraypool(sizeof(point), 8);
18429  // This is a global array used by refineregion().
18430  encseglist = new arraypool(sizeof(face), 4);
18431 
18432  facetcount = 0;
18433 
18434  while (subfacstack->objects > 0l) {
18435 
18436  subfacstack->objects--;
18437  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
18438  searchsh = *parysh;
18439 
18440  if (searchsh.sh[3] == NULL) continue; // It is dead.
18441  if (isshtet(searchsh)) continue; // It is recovered.
18442 
18443  // Collect all unrecovered subfaces which are co-facet.
18444  smarktest(searchsh);
18445  tg_facfaces->newindex((void **) &parysh);
18446  *parysh = searchsh;
18447  for (i = 0; i < tg_facfaces->objects; i++) {
18448  parysh = (face *) fastlookup(tg_facfaces, i);
18449  for (j = 0; j < 3; j++) {
18450  if (!isshsubseg(*parysh)) {
18451  spivot(*parysh, searchsh);
18452  if (!smarktested(searchsh)) {
18453  if (!isshtet(searchsh)) {
18454  smarktest(searchsh);
18455  tg_facfaces->newindex((void **) &parysh1);
18456  *parysh1 = searchsh;
18457  }
18458  }
18459  }
18460  senextself(*parysh);
18461  } // j
18462  } // i
18463  // Have found all facet subfaces. Unmark them.
18464  for (i = 0; i < tg_facfaces->objects; i++) {
18465  parysh = (face *) fastlookup(tg_facfaces, i);
18466  sunmarktest(*parysh);
18467  }
18468 
18469  if (b->verbose > 1) {
18470  printf(" Recovering facet #%d: %ld subfaces.\n", facetcount + 1,
18471  tg_facfaces->objects);
18472  }
18473  facetcount++;
18474 
18475  while (tg_facfaces->objects > 0l) {
18476 
18477  tg_facfaces->objects--;
18478  parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
18479  searchsh = *parysh;
18480 
18481  if (searchsh.sh[3] == NULL) continue; // It is dead.
18482  if (isshtet(searchsh)) continue; // It is recovered.
18483 
18484  searchtet.tet = NULL;
18485  if (scoutsubface(&searchsh, &searchtet, 1)) continue;
18486 
18487  // The subface is missing. Form the missing region.
18488  // Re-use 'tg_crosstets' for 'adjtets'.
18489  formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
18490 
18491  int searchflag = scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs);
18492  if (searchflag > 0) {
18493  // Save this crossing edge, will be used by fillcavity().
18494  crossedge = searchtet;
18495  // Form a cavity of crossing tets.
18496  success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
18497  tg_topfaces, tg_botfaces, tg_toppoints,
18498  tg_botpoints);
18499  if (success) {
18500  if (!b->flipinsert) {
18501  // Tetrahedralize the top part. Re-use 'tg_midfaces'.
18502  delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
18503  tg_topnewtets, tg_crosstets, tg_midfaces);
18504  // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
18505  delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
18506  tg_botnewtets, tg_crosstets, tg_midfaces);
18507  // Fill the cavity with new tets.
18508  success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
18509  tg_missingshs, tg_topnewtets, tg_botnewtets,
18510  &crossedge);
18511  if (success) {
18512  // Cavity is remeshed. Delete old tets and outer new tets.
18513  carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
18514  } else {
18515  restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18516  tg_missingshbds);
18517  }
18518  } else {
18519  // Use the flip algorithm of Shewchuk to recover the subfaces.
18520  flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints,
18521  tg_missingshverts);
18522  // Put all subfaces in R back to tg_facfaces.
18523  for (i = 0; i < tg_missingshs->objects; i++) {
18524  parysh = (face *) fastlookup(tg_missingshs, i);
18525  tg_facfaces->newindex((void **) &parysh1);
18526  *parysh1 = *parysh;
18527  }
18528  success = 1;
18529  // Clear working lists.
18530  tg_crosstets->restart();
18531  tg_topfaces->restart();
18532  tg_botfaces->restart();
18533  tg_toppoints->restart();
18534  tg_botpoints->restart();
18535  } // b->flipinsert
18536 
18537  if (success) {
18538  // Recover interior subfaces.
18539  for (i = 0; i < caveencshlist->objects; i++) {
18540  parysh = (face *) fastlookup(caveencshlist, i);
18541  if (!scoutsubface(parysh, &searchtet, 1)) {
18542  // Add this face at the end of the list, so it will be
18543  // processed immediately.
18544  tg_facfaces->newindex((void **) &parysh1);
18545  *parysh1 = *parysh;
18546  }
18547  }
18548  caveencshlist->restart();
18549  // Recover interior segments. This should always be recovered.
18550  for (i = 0; i < caveencseglist->objects; i++) {
18551  paryseg = (face *) fastlookup(caveencseglist, i);
18552  dir = scoutsegment(sorg(*paryseg), sdest(*paryseg), paryseg,
18553  &searchtet, NULL, NULL);
18554  if (dir != SHAREEDGE) {
18555  terminatetetgen(this, 2);
18556  }
18557  // Insert this segment.
18558  // Let the segment remember an adjacent tet.
18559  sstbond1(*paryseg, searchtet);
18560  // Bond the segment to all tets containing it.
18561  neightet = searchtet;
18562  do {
18563  tssbond1(neightet, *paryseg);
18564  fnextself(neightet);
18565  } while (neightet.tet != searchtet.tet);
18566  }
18567  caveencseglist->restart();
18568  } // success - remesh cavity
18569  } // success - form cavity
18570  else {
18571  terminatetetgen(this, 2); // Report a bug.
18572  } // Not success - form cavity
18573  } else {
18574  // Put all subfaces in R back to tg_facfaces.
18575  for (i = 0; i < tg_missingshs->objects; i++) {
18576  parysh = (face *) fastlookup(tg_missingshs, i);
18577  tg_facfaces->newindex((void **) &parysh1);
18578  *parysh1 = *parysh;
18579  }
18580  if (searchflag != -1) {
18581  // Some edge(s) in the missing regions were flipped.
18582  success = 1;
18583  } else {
18584  restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18585  tg_missingshbds); // Only remove fake segments.
18586  // Choose an edge to split (set in recentsh)
18587  recentsh = searchsh;
18588  success = 0; // Do refineregion();
18589  }
18590  } // if (scoutcrossedge)
18591 
18592  // Unmarktest all points of the missing region.
18593  for (i = 0; i < tg_missingshverts->objects; i++) {
18594  parypt = (point *) fastlookup(tg_missingshverts, i);
18595  punmarktest(*parypt);
18596  }
18597  tg_missingshverts->restart();
18598  tg_missingshbds->restart();
18599  tg_missingshs->restart();
18600 
18601  if (!success) {
18602  // The missing region can not be recovered. Refine it.
18603  refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
18604  tg_topnewtets, tg_crosstets, tg_midfaces);
18605  }
18606  } // while (tg_facfaces->objects)
18607 
18608  } // while ((subfacstack->objects)
18609 
18610  // Accumulate the dynamic memory.
18611  totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
18612  tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
18613  tg_botfaces->totalmemory + tg_midfaces->totalmemory +
18614  tg_toppoints->totalmemory + tg_botpoints->totalmemory +
18615  tg_facfaces->totalmemory + tg_topshells->totalmemory +
18616  tg_botshells->totalmemory + tg_missingshs->totalmemory +
18617  tg_missingshbds->totalmemory +
18618  tg_missingshverts->totalmemory +
18619  encseglist->totalmemory);
18620 
18621  // Delete arrays.
18622  delete tg_crosstets;
18623  delete tg_topnewtets;
18624  delete tg_botnewtets;
18625  delete tg_topfaces;
18626  delete tg_botfaces;
18627  delete tg_midfaces;
18628  delete tg_toppoints;
18629  delete tg_botpoints;
18630  delete tg_facfaces;
18631  delete tg_topshells;
18632  delete tg_botshells;
18633  delete tg_missingshs;
18634  delete tg_missingshbds;
18635  delete tg_missingshverts;
18636  delete encseglist;
18637  encseglist = NULL;
18638 }
18639 
18641 // //
18642 // constraineddelaunay() Create a constrained Delaunay tetrahedralization.//
18643 // //
18645 
18646 void tetgenmesh::constraineddelaunay(clock_t& tv)
18647 {
18648  face searchsh, *parysh;
18649  face searchseg, *paryseg;
18650  int s, i;
18651 
18652  // Statistics.
18653  long bakfillregioncount;
18654  long bakcavitycount, bakcavityexpcount;
18655  long bakseg_ref_count;
18656 
18657  if (!b->quiet) {
18658  printf("Constrained Delaunay...\n");
18659  }
18660 
18661  makesegmentendpointsmap();
18662  makefacetverticesmap();
18663 
18664  if (b->verbose) {
18665  printf(" Delaunizing segments.\n");
18666  }
18667 
18668  checksubsegflag = 1;
18669 
18670  // Put all segments into the list (in random order).
18671  subsegs->traversalinit();
18672  for (i = 0; i < subsegs->items; i++) {
18673  s = randomnation(i + 1);
18674  // Move the s-th seg to the i-th.
18675  subsegstack->newindex((void **) &paryseg);
18676  *paryseg = * (face *) fastlookup(subsegstack, s);
18677  // Put i-th seg to be the s-th.
18678  searchseg.sh = shellfacetraverse(subsegs);
18679  //sinfect(searchseg); // Only save it once.
18680  paryseg = (face *) fastlookup(subsegstack, s);
18681  *paryseg = searchseg;
18682  }
18683 
18684  // Recover non-Delaunay segments.
18685  delaunizesegments();
18686 
18687  if (b->verbose) {
18688  printf(" Inserted %ld Steiner points.\n", st_segref_count);
18689  }
18690 
18691  tv = clock();
18692 
18693  if (b->verbose) {
18694  printf(" Constraining facets.\n");
18695  }
18696 
18697  // Subfaces will be introduced.
18698  checksubfaceflag = 1;
18699 
18700  bakfillregioncount = fillregioncount;
18701  bakcavitycount = cavitycount;
18702  bakcavityexpcount = cavityexpcount;
18703  bakseg_ref_count = st_segref_count;
18704 
18705  // Randomly order the subfaces.
18706  subfaces->traversalinit();
18707  for (i = 0; i < subfaces->items; i++) {
18708  s = randomnation(i + 1);
18709  // Move the s-th subface to the i-th.
18710  subfacstack->newindex((void **) &parysh);
18711  *parysh = * (face *) fastlookup(subfacstack, s);
18712  // Put i-th subface to be the s-th.
18713  searchsh.sh = shellfacetraverse(subfaces);
18714  parysh = (face *) fastlookup(subfacstack, s);
18715  *parysh = searchsh;
18716  }
18717 
18718  // Recover facets.
18719  constrainedfacets();
18720 
18721  if (b->verbose) {
18722  if (fillregioncount > bakfillregioncount) {
18723  printf(" Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
18724  }
18725  if (cavitycount > bakcavitycount) {
18726  printf(" Remeshed %ld cavities", cavitycount - bakcavitycount);
18727  if (cavityexpcount - bakcavityexpcount) {
18728  printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
18729  }
18730  printf(".\n");
18731  }
18732  if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
18733  printf(" Inserted %ld (%ld, %ld) refine points.\n",
18734  st_segref_count + st_facref_count - bakseg_ref_count,
18735  st_segref_count - bakseg_ref_count, st_facref_count);
18736  }
18737  }
18738 }
18739 
18743 
18747 
18749 // //
18750 // checkflipeligibility() A call back function for boundary recovery. //
18751 // //
18752 // 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
18753 // and 2 : 3-to-2, respectively. //
18754 // //
18755 // 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is //
18756 // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
18757 // other points must not be 'dummypoint'. //
18758 // //
18760 
18761 int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
18762  point pc, point pd, point pe,
18763  int level, int edgepivot,
18764  flipconstraints* fc)
18765 {
18766  point tmppts[3];
18767  enum interresult dir;
18768  int types[2], poss[4];
18769  int intflag;
18770  int rejflag = 0;
18771  int i;
18772 
18773  if (fc->seg[0] != NULL) {
18774  // A constraining edge is given (e.g., for edge recovery).
18775  if (fliptype == 1) {
18776  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18777  tmppts[0] = pa;
18778  tmppts[1] = pb;
18779  tmppts[2] = pc;
18780  for (i = 0; i < 3 && !rejflag; i++) {
18781  if (tmppts[i] != dummypoint) {
18782  // Test if the face [e,d,#] intersects the edge.
18783  intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1],
18784  NULL, 1, types, poss);
18785  if (intflag == 2) {
18786  // They intersect at a single point.
18787  dir = (enum interresult) types[0];
18788  if (dir == ACROSSFACE) {
18789  // The interior of [e,d,#] intersect the segment.
18790  rejflag = 1;
18791  } else if (dir == ACROSSEDGE) {
18792  if (poss[0] == 0) {
18793  // The interior of [e,d] intersect the segment.
18794  // Since [e,d] is the newly created edge. Reject this flip.
18795  rejflag = 1;
18796  }
18797  }
18798  } else if (intflag == 4) {
18799  // They may intersect at either a point or a line segment.
18800  dir = (enum interresult) types[0];
18801  if (dir == ACROSSEDGE) {
18802  if (poss[0] == 0) {
18803  // The interior of [e,d] intersect the segment.
18804  // Since [e,d] is the newly created edge. Reject this flip.
18805  rejflag = 1;
18806  }
18807  }
18808  }
18809  } // if (tmppts[0] != dummypoint)
18810  } // i
18811  } else if (fliptype == 2) {
18812  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18813  if (pc != dummypoint) {
18814  // Check if the new face [a,b,c] intersect the edge in its interior.
18815  intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL,
18816  1, types, poss);
18817  if (intflag == 2) {
18818  // They intersect at a single point.
18819  dir = (enum interresult) types[0];
18820  if (dir == ACROSSFACE) {
18821  // The interior of [a,b,c] intersect the segment.
18822  rejflag = 1; // Do not flip.
18823  }
18824  } else if (intflag == 4) {
18825  // [a,b,c] is coplanar with the edge.
18826  dir = (enum interresult) types[0];
18827  if (dir == ACROSSEDGE) {
18828  // The boundary of [a,b,c] intersect the segment.
18829  rejflag = 1; // Do not flip.
18830  }
18831  }
18832  } // if (pc != dummypoint)
18833  }
18834  } // if (fc->seg[0] != NULL)
18835 
18836  if ((fc->fac[0] != NULL) && !rejflag) {
18837  // A constraining face is given (e.g., for face recovery).
18838  if (fliptype == 1) {
18839  // A 2-to-3 flip.
18840  // Test if the new edge [e,d] intersects the face.
18841  intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd,
18842  NULL, 1, types, poss);
18843  if (intflag == 2) {
18844  // They intersect at a single point.
18845  dir = (enum interresult) types[0];
18846  if (dir == ACROSSFACE) {
18847  rejflag = 1;
18848  } else if (dir == ACROSSEDGE) {
18849  rejflag = 1;
18850  }
18851  } else if (intflag == 4) {
18852  // The edge [e,d] is coplanar with the face.
18853  // There may be two intersections.
18854  for (i = 0; i < 2 && !rejflag; i++) {
18855  dir = (enum interresult) types[i];
18856  if (dir == ACROSSFACE) {
18857  rejflag = 1;
18858  } else if (dir == ACROSSEDGE) {
18859  rejflag = 1;
18860  }
18861  }
18862  }
18863  } // if (fliptype == 1)
18864  } // if (fc->fac[0] != NULL)
18865 
18866  if ((fc->remvert != NULL) && !rejflag) {
18867  // The vertex is going to be removed. Do not create a new edge which
18868  // contains this vertex.
18869  if (fliptype == 1) {
18870  // A 2-to-3 flip.
18871  if ((pd == fc->remvert) || (pe == fc->remvert)) {
18872  rejflag = 1;
18873  }
18874  }
18875  }
18876 
18877  if (fc->remove_large_angle && !rejflag) {
18878  // Remove a large dihedral angle. Do not create a new small angle.
18879  REAL cosmaxd = 0, diff;
18880  if (fliptype == 1) {
18881  // We assume that neither 'a' nor 'b' is dummypoint.
18882  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18883  // The new tet [e,d,a,b] will be flipped later. Only two new tets:
18884  // [e,d,b,c] and [e,d,c,a] need to be checked.
18885  if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
18886  // Get the largest dihedral angle of [e,d,b,c].
18887  tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
18888  diff = cosmaxd - fc->cosdihed_in;
18889  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18890  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18891  rejflag = 1;
18892  } else {
18893  // Record the largest new angle.
18894  if (cosmaxd < fc->cosdihed_out) {
18895  fc->cosdihed_out = cosmaxd;
18896  }
18897  // Get the largest dihedral angle of [e,d,c,a].
18898  tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
18899  diff = cosmaxd - fc->cosdihed_in;
18900  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18901  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18902  rejflag = 1;
18903  } else {
18904  // Record the largest new angle.
18905  if (cosmaxd < fc->cosdihed_out) {
18906  fc->cosdihed_out = cosmaxd;
18907  }
18908  }
18909  }
18910  } // if (pc != dummypoint && ...)
18911  } else if (fliptype == 2) {
18912  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18913  // We assume that neither 'e' nor 'd' is dummypoint.
18914  if (level == 0) {
18915  // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
18916  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18917  // Get the largest dihedral angle of [a,b,c,d].
18918  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18919  diff = cosmaxd - fc->cosdihed_in;
18920  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
18921  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18922  rejflag = 1;
18923  } else {
18924  // Record the largest new angle.
18925  if (cosmaxd < fc->cosdihed_out) {
18926  fc->cosdihed_out = cosmaxd;
18927  }
18928  // Get the largest dihedral angle of [b,a,c,e].
18929  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18930  diff = cosmaxd - fc->cosdihed_in;
18931  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18932  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18933  rejflag = 1;
18934  } else {
18935  // Record the largest new angle.
18936  if (cosmaxd < fc->cosdihed_out) {
18937  fc->cosdihed_out = cosmaxd;
18938  }
18939  }
18940  }
18941  }
18942  } else { // level > 0
18943  if (edgepivot == 1) {
18944  // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
18945  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18946  // Get the largest dihedral angle of [b,a,c,e].
18947  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18948  diff = cosmaxd - fc->cosdihed_in;
18949  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18950  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18951  rejflag = 1;
18952  } else {
18953  // Record the largest new angle.
18954  if (cosmaxd < fc->cosdihed_out) {
18955  fc->cosdihed_out = cosmaxd;
18956  }
18957  }
18958  }
18959  } else {
18960  // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
18961  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18962  // Get the largest dihedral angle of [b,a,c,e].
18963  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18964  diff = cosmaxd - fc->cosdihed_in;
18965  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18966  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18967  rejflag = 1;
18968  } else {
18969  // Record the largest new angle.
18970  if (cosmaxd < fc->cosdihed_out) {
18971  fc->cosdihed_out = cosmaxd;
18972  }
18973  }
18974  }
18975  } // edgepivot
18976  } // level
18977  }
18978  }
18979 
18980  return rejflag;
18981 }
18982 
18984 // //
18985 // removeedgebyflips() Attempt to remove an edge by flips. //
18986 // //
18987 // 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed. //
18988 // //
18989 // The return value is a positive integer, it indicates whether the edge is //
18990 // removed or not. A value "2" means the edge is removed, otherwise, the //
18991 // edge is not removed and the value (must >= 3) is the current number of //
18992 // tets in the edge star. //
18993 // //
18995 
18996 int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
18997 {
18998  triface *abtets, spintet;
18999  int t1ver;
19000  int n, nn, i;
19001 
19002 
19003  if (checksubsegflag) {
19004  // Do not flip a segment.
19005  if (issubseg(*flipedge)) {
19006  if (fc->collectencsegflag) {
19007  face checkseg, *paryseg;
19008  tsspivot1(*flipedge, checkseg);
19009  if (!sinfected(checkseg)) {
19010  // Queue this segment in list.
19011  sinfect(checkseg);
19012  caveencseglist->newindex((void **) &paryseg);
19013  *paryseg = checkseg;
19014  }
19015  }
19016  return 0;
19017  }
19018  }
19019 
19020  // Count the number of tets at edge [a,b].
19021  n = 0;
19022  spintet = *flipedge;
19023  while (1) {
19024  n++;
19025  fnextself(spintet);
19026  if (spintet.tet == flipedge->tet) break;
19027  }
19028  if (n < 3) {
19029  // It is only possible when the mesh contains inverted tetrahedra.
19030  terminatetetgen(this, 2); // Report a bug
19031  }
19032 
19033  if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
19034  // The star size exceeds the limit.
19035  return 0; // Do not flip it.
19036  }
19037 
19038  // Allocate spaces.
19039  abtets = new triface[n];
19040  // Collect the tets at edge [a,b].
19041  spintet = *flipedge;
19042  i = 0;
19043  while (1) {
19044  abtets[i] = spintet;
19045  setelemcounter(abtets[i], 1);
19046  i++;
19047  fnextself(spintet);
19048  if (spintet.tet == flipedge->tet) break;
19049  }
19050 
19051 
19052  // Try to flip the edge (level = 0, edgepivot = 0).
19053  nn = flipnm(abtets, n, 0, 0, fc);
19054 
19055 
19056  if (nn > 2) {
19057  // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
19058  for (i = 0; i < nn; i++) {
19059  setelemcounter(abtets[i], 0);
19060  }
19061  // Restore the input edge (needed by Lawson's flip).
19062  *flipedge = abtets[0];
19063  }
19064 
19065  // Release the temporary allocated spaces.
19066  // NOTE: fc->unflip must be 0.
19067  int bakunflip = fc->unflip;
19068  fc->unflip = 0;
19069  flipnm_post(abtets, n, nn, 0, fc);
19070  fc->unflip = bakunflip;
19071 
19072  delete [] abtets;
19073 
19074  return nn;
19075 }
19076 
19078 // //
19079 // removefacebyflips() Remove a face by flips. //
19080 // //
19081 // Return 1 if the face is removed. Otherwise, return 0. //
19082 // //
19083 // ASSUMPTIONS: //
19084 // - 'flipface' must not be a subface. //
19085 // - 'flipface' must not be a hull face. //
19086 // //
19088 
19089 int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
19090 {
19091  triface fliptets[3], flipedge;
19092  point pa, pb, pc, pd, pe;
19093  REAL ori;
19094  int reducflag = 0;
19095 
19096  fliptets[0] = *flipface;
19097  fsym(*flipface, fliptets[1]);
19098  pa = org(fliptets[0]);
19099  pb = dest(fliptets[0]);
19100  pc = apex(fliptets[0]);
19101  pd = oppo(fliptets[0]);
19102  pe = oppo(fliptets[1]);
19103 
19104  ori = orient3d(pa, pb, pd, pe);
19105  if (ori > 0) {
19106  ori = orient3d(pb, pc, pd, pe);
19107  if (ori > 0) {
19108  ori = orient3d(pc, pa, pd, pe);
19109  if (ori > 0) {
19110  // Found a 2-to-3 flip.
19111  reducflag = 1;
19112  } else {
19113  eprev(*flipface, flipedge); // [c,a]
19114  }
19115  } else {
19116  enext(*flipface, flipedge); // [b,c]
19117  }
19118  } else {
19119  flipedge = *flipface; // [a,b]
19120  }
19121 
19122  if (reducflag) {
19123  // A 2-to-3 flip is found.
19124  flip23(fliptets, 0, fc);
19125  return 1;
19126  } else {
19127  // Try to flip the selected edge of this face.
19128  if (removeedgebyflips(&flipedge, fc) == 2) {
19129  return 1;
19130  }
19131  }
19132 
19133  // Face is not removed.
19134  return 0;
19135 }
19136 
19138 // //
19139 // recoveredge() Recover an edge in current tetrahedralization. //
19140 // //
19141 // If the edge is recovered, 'searchtet' returns a tet containing the edge. //
19142 // //
19143 // This edge may intersect a set of faces and edges in the mesh. All these //
19144 // faces or edges are needed to be removed. //
19145 // //
19146 // If the parameter 'fullsearch' is set, it tries to flip any face or edge //
19147 // that intersects the recovering edge. Otherwise, only the face or edge //
19148 // which is visible by 'startpt' is tried. //
19149 // //
19150 // The parameter 'sedge' is used to report self-intersection. If it is not //
19151 // a NULL, it is EITHER a segment OR a subface that contains this edge. //
19152 // //
19153 // Note that this routine assumes that the tetrahedralization is convex. //
19154 // //
19156 
19157 int tetgenmesh::recoveredgebyflips(point startpt, point endpt, face *sedge,
19158  triface* searchtet, int fullsearch)
19159 {
19160  flipconstraints fc;
19161  enum interresult dir;
19162 
19163  fc.seg[0] = startpt;
19164  fc.seg[1] = endpt;
19165  fc.checkflipeligibility = 1;
19166 
19167  // The mainloop of the edge reocvery.
19168  while (1) { // Loop I
19169 
19170  // Search the edge from 'startpt'.
19171  point2tetorg(startpt, *searchtet);
19172  dir = finddirection(searchtet, endpt);
19173  if (dir == ACROSSVERT) {
19174  if (dest(*searchtet) == endpt) {
19175  return 1; // Edge is recovered.
19176  } else {
19177  if (sedge) {
19178  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19179  } else {
19180  return 0;
19181  }
19182  }
19183  }
19184 
19185  // The edge is missing.
19186 
19187  // Try to remove the first intersecting face/edge.
19188  enextesymself(*searchtet); // Go to the opposite face.
19189  if (dir == ACROSSFACE) {
19190  if (checksubfaceflag) {
19191  if (issubface(*searchtet)) {
19192  if (sedge) {
19193  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19194  } else {
19195  return 0; // Cannot flip a subface.
19196  }
19197  }
19198  }
19199  // Try to flip a crossing face.
19200  if (removefacebyflips(searchtet, &fc)) {
19201  continue;
19202  }
19203  } else if (dir == ACROSSEDGE) {
19204  if (checksubsegflag) {
19205  if (issubseg(*searchtet)) {
19206  if (sedge) {
19207  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19208  } else {
19209  return 0; // Cannot flip a segment.
19210  }
19211  }
19212  }
19213  // Try to flip an intersecting edge.
19214  if (removeedgebyflips(searchtet, &fc) == 2) {
19215  continue;
19216  }
19217  }
19218 
19219  // The edge is missing.
19220 
19221  if (fullsearch) {
19222  // Try to flip one of the faces/edges which intersects the edge.
19223  triface neightet, spintet;
19224  point pa, pb, pc, pd;
19225  badface bakface;
19226  enum interresult dir1;
19227  int types[2], poss[4], pos = 0;
19228  int success = 0;
19229  int t1ver;
19230  int i, j;
19231 
19232  // Loop through the sequence of intersecting faces/edges from
19233  // 'startpt' to 'endpt'.
19234  point2tetorg(startpt, *searchtet);
19235  dir = finddirection(searchtet, endpt);
19236 
19237  // Go to the face/edge intersecting the searching edge.
19238  enextesymself(*searchtet); // Go to the opposite face.
19239  // This face/edge has been tried in previous step.
19240 
19241  while (1) { // Loop I-I
19242 
19243  // Find the next intersecting face/edge.
19244  fsymself(*searchtet);
19245  if (dir == ACROSSFACE) {
19246  neightet = *searchtet;
19247  j = (neightet.ver & 3); // j is the current face number.
19248  for (i = j + 1; i < j + 4; i++) {
19249  neightet.ver = (i % 4);
19250  pa = org(neightet);
19251  pb = dest(neightet);
19252  pc = apex(neightet);
19253  pd = oppo(neightet); // The above point.
19254  if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
19255  dir = (enum interresult) types[0];
19256  pos = poss[0];
19257  break;
19258  } else {
19259  dir = DISJOINT;
19260  pos = 0;
19261  }
19262  } // i
19263  // There must be an intersection face/edge.
19264  if (dir == DISJOINT) {
19265  terminatetetgen(this, 2);
19266  }
19267  } else if (dir == ACROSSEDGE) {
19268  while (1) { // Loop I-I-I
19269  // Check the two opposite faces (of the edge) in 'searchtet'.
19270  for (i = 0; i < 2; i++) {
19271  if (i == 0) {
19272  enextesym(*searchtet, neightet);
19273  } else {
19274  eprevesym(*searchtet, neightet);
19275  }
19276  pa = org(neightet);
19277  pb = dest(neightet);
19278  pc = apex(neightet);
19279  pd = oppo(neightet); // The above point.
19280  if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
19281  dir = (enum interresult) types[0];
19282  pos = poss[0];
19283  break; // for loop
19284  } else {
19285  dir = DISJOINT;
19286  pos = 0;
19287  }
19288  } // i
19289  if (dir != DISJOINT) {
19290  // Find an intersection face/edge.
19291  break; // Loop I-I-I
19292  }
19293  // No intersection. Rotate to the next tet at the edge.
19294  fnextself(*searchtet);
19295  } // while (1) // Loop I-I-I
19296  } else {
19297  terminatetetgen(this, 2); // Report a bug
19298  }
19299 
19300  // Adjust to the intersecting edge/vertex.
19301  for (i = 0; i < pos; i++) {
19302  enextself(neightet);
19303  }
19304 
19305  if (dir == SHAREVERT) {
19306  // Check if we have reached the 'endpt'.
19307  pd = org(neightet);
19308  if (pd == endpt) {
19309  // Failed to recover the edge.
19310  break; // Loop I-I
19311  } else {
19312  terminatetetgen(this, 2); // Report a bug
19313  }
19314  }
19315 
19316  // The next to be flipped face/edge.
19317  *searchtet = neightet;
19318 
19319  // Bakup this face (tetrahedron).
19320  bakface.forg = org(*searchtet);
19321  bakface.fdest = dest(*searchtet);
19322  bakface.fapex = apex(*searchtet);
19323  bakface.foppo = oppo(*searchtet);
19324 
19325  // Try to flip this intersecting face/edge.
19326  if (dir == ACROSSFACE) {
19327  if (checksubfaceflag) {
19328  if (issubface(*searchtet)) {
19329  if (sedge) {
19330  return report_selfint_edge(startpt,endpt,sedge,searchtet,dir);
19331  } else {
19332  return 0; // Cannot flip a subface.
19333  }
19334  }
19335  }
19336  if (removefacebyflips(searchtet, &fc)) {
19337  success = 1;
19338  break; // Loop I-I
19339  }
19340  } else if (dir == ACROSSEDGE) {
19341  if (checksubsegflag) {
19342  if (issubseg(*searchtet)) {
19343  if (sedge) {
19344  return report_selfint_edge(startpt,endpt,sedge,searchtet,dir);
19345  } else {
19346  return 0; // Cannot flip a segment.
19347  }
19348  }
19349  }
19350  if (removeedgebyflips(searchtet, &fc) == 2) {
19351  success = 1;
19352  break; // Loop I-I
19353  }
19354  } else if (dir == ACROSSVERT) {
19355  if (sedge) {
19356  //return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19357  terminatetetgen(this, 2);
19358  } else {
19359  return 0;
19360  }
19361  } else {
19362  terminatetetgen(this, 2);
19363  }
19364 
19365  // The face/edge is not flipped.
19366  if ((searchtet->tet == NULL) ||
19367  (org(*searchtet) != bakface.forg) ||
19368  (dest(*searchtet) != bakface.fdest) ||
19369  (apex(*searchtet) != bakface.fapex) ||
19370  (oppo(*searchtet) != bakface.foppo)) {
19371  // 'searchtet' was flipped. We must restore it.
19372  point2tetorg(bakface.forg, *searchtet);
19373  dir1 = finddirection(searchtet, bakface.fdest);
19374  if (dir1 == ACROSSVERT) {
19375  if (dest(*searchtet) == bakface.fdest) {
19376  spintet = *searchtet;
19377  while (1) {
19378  if (apex(spintet) == bakface.fapex) {
19379  // Found the face.
19380  *searchtet = spintet;
19381  break;
19382  }
19383  fnextself(spintet);
19384  if (spintet.tet == searchtet->tet) {
19385  searchtet->tet = NULL;
19386  break; // Not find.
19387  }
19388  } // while (1)
19389  if (searchtet->tet != NULL) {
19390  if (oppo(*searchtet) != bakface.foppo) {
19391  fsymself(*searchtet);
19392  if (oppo(*searchtet) != bakface.foppo) {
19393  // The original (intersecting) tet has been flipped.
19394  searchtet->tet = NULL;
19395  break; // Not find.
19396  }
19397  }
19398  }
19399  } else {
19400  searchtet->tet = NULL; // Not find.
19401  }
19402  } else {
19403  searchtet->tet = NULL; // Not find.
19404  }
19405  if (searchtet->tet == NULL) {
19406  success = 0; // This face/edge has been destroyed.
19407  break; // Loop I-I
19408  }
19409  }
19410  } // while (1) // Loop I-I
19411 
19412  if (success) {
19413  // One of intersecting faces/edges is flipped.
19414  continue;
19415  }
19416 
19417  } // if (fullsearch)
19418 
19419  // The edge is missing.
19420  break; // Loop I
19421 
19422  } // while (1) // Loop I
19423 
19424  return 0;
19425 }
19426 
19428 // //
19429 // add_steinerpt_in_schoenhardtpoly() Insert a Steiner point in a Schoen- //
19430 // hardt polyhedron. //
19431 // //
19432 // 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
19433 // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)]. Moreover, //
19434 // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'. A special //
19435 // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b]. //
19436 // Such set of tets arises when we want to recover an edge from 'p0' to 'p_ //
19437 // (n-1)', and the number of tets at [a,b] can not be reduced by any flip. //
19438 // //
19440 
19441 int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
19442  int chkencflag)
19443 {
19444  triface worktet, *parytet;
19445  triface faketet1, faketet2;
19446  point pc, pd, steinerpt;
19447  insertvertexflags ivf;
19448  optparameters opm;
19449  REAL vcd[3], sampt[3], smtpt[3];
19450  REAL maxminvol = 0.0, minvol = 0.0, ori;
19451  int success, maxidx = 0;
19452  int it, i;
19453 
19454 
19455  pc = apex(abtets[0]); // pc = p0
19456  pd = oppo(abtets[n-1]); // pd = p_(n-1)
19457 
19458 
19459  // Find an optimial point in edge [c,d]. It is visible by all outer faces
19460  // of 'abtets', and it maxmizes the min volume.
19461 
19462  // initialize the list of 2n boundary faces.
19463  for (i = 0; i < n; i++) {
19464  edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
19465  cavetetlist->newindex((void **) &parytet);
19466  *parytet = worktet;
19467  eorgoppo(abtets[i], worktet); // [p_i+1,p_i,b]
19468  cavetetlist->newindex((void **) &parytet);
19469  *parytet = worktet;
19470  }
19471 
19472  int N = 100;
19473  REAL stepi = 0.01;
19474 
19475  // Search the point along the edge [c,d].
19476  for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
19477 
19478  // Sample N points in edge [c,d].
19479  for (it = 1; it < N; it++) {
19480  for (i = 0; i < 3; i++) {
19481  sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
19482  }
19483  for (i = 0; i < cavetetlist->objects; i++) {
19484  parytet = (triface *) fastlookup(cavetetlist, i);
19485  ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
19486  if (i == 0) {
19487  minvol = ori;
19488  } else {
19489  if (minvol > ori) minvol = ori;
19490  }
19491  } // i
19492  if (it == 1) {
19493  maxminvol = minvol;
19494  maxidx = it;
19495  } else {
19496  if (maxminvol < minvol) {
19497  maxminvol = minvol;
19498  maxidx = it;
19499  }
19500  }
19501  } // it
19502 
19503  if (maxminvol <= 0) {
19504  cavetetlist->restart();
19505  return 0;
19506  }
19507 
19508  for (i = 0; i < 3; i++) {
19509  smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
19510  }
19511 
19512  // Create two faked tets to hold the two non-existing boundary faces:
19513  // [d,c,a] and [c,d,b].
19514  maketetrahedron(&faketet1);
19515  setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
19516  cavetetlist->newindex((void **) &parytet);
19517  *parytet = faketet1;
19518  maketetrahedron(&faketet2);
19519  setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
19520  cavetetlist->newindex((void **) &parytet);
19521  *parytet = faketet2;
19522 
19523  // Point smooth options.
19524  opm.max_min_volume = 1;
19525  opm.numofsearchdirs = 20;
19526  opm.searchstep = 0.001;
19527  opm.maxiter = 100; // Limit the maximum iterations.
19528  opm.initval = 0.0; // Initial volume is zero.
19529 
19530  // Try to relocate the point into the inside of the polyhedron.
19531  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
19532 
19533  if (success) {
19534  while (opm.smthiter == 100) {
19535  // It was relocated and the prescribed maximum iteration reached.
19536  // Try to increase the search stepsize.
19537  opm.searchstep *= 10.0;
19538  //opm.maxiter = 100; // Limit the maximum iterations.
19539  opm.initval = opm.imprval;
19540  opm.smthiter = 0; // Init.
19541  smoothpoint(smtpt, cavetetlist, 1, &opm);
19542  }
19543  } // if (success)
19544 
19545  // Delete the two faked tets.
19546  tetrahedrondealloc(faketet1.tet);
19547  tetrahedrondealloc(faketet2.tet);
19548 
19549  cavetetlist->restart();
19550 
19551  if (!success) {
19552  return 0;
19553  }
19554 
19555 
19556  // Insert the Steiner point.
19557  makepoint(&steinerpt, FREEVOLVERTEX);
19558  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
19559 
19560  // Insert the created Steiner point.
19561  for (i = 0; i < n; i++) {
19562  infect(abtets[i]);
19563  caveoldtetlist->newindex((void **) &parytet);
19564  *parytet = abtets[i];
19565  }
19566  worktet = abtets[0]; // No need point location.
19567  ivf.iloc = (int) INSTAR;
19568  ivf.chkencflag = chkencflag;
19569  ivf.assignmeshsize = b->metric;
19570  if (ivf.assignmeshsize) {
19571  // Search the tet containing 'steinerpt' for size interpolation.
19572  locate(steinerpt, &(abtets[0]));
19573  worktet = abtets[0];
19574  }
19575 
19576  // Insert the new point into the tetrahedralization T.
19577  // Note that T is convex (nonconvex = 0).
19578  if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
19579  // The vertex has been inserted.
19580  st_volref_count++;
19581  if (steinerleft > 0) steinerleft--;
19582  return 1;
19583  } else {
19584  // Not inserted.
19585  pointdealloc(steinerpt);
19586  return 0;
19587  }
19588 }
19589 
19591 // //
19592 // add_steinerpt_in_segment() Add a Steiner point inside a segment. //
19593 // //
19595 
19596 int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
19597 {
19598  triface searchtet;
19599  face *paryseg, candseg;
19600  point startpt, endpt, pc, pd;
19601  flipconstraints fc;
19602  enum interresult dir;
19603  REAL P[3], Q[3], tp, tq;
19604  REAL len, smlen = 0, split = 0, split_q = 0;
19605  int success;
19606  int i;
19607 
19608  startpt = sorg(*misseg);
19609  endpt = sdest(*misseg);
19610 
19611  fc.seg[0] = startpt;
19612  fc.seg[1] = endpt;
19613  fc.checkflipeligibility = 1;
19614  fc.collectencsegflag = 1;
19615 
19616  point2tetorg(startpt, searchtet);
19617  dir = finddirection(&searchtet, endpt);
19618  // Try to flip the first intersecting face/edge.
19619  enextesymself(searchtet); // Go to the opposite face.
19620 
19621  int bak_fliplinklevel = b->fliplinklevel;
19622  b->fliplinklevel = searchlevel;
19623 
19624  if (dir == ACROSSFACE) {
19625  // A face is intersected with the segment. Try to flip it.
19626  success = removefacebyflips(&searchtet, &fc);
19627  } else if (dir == ACROSSEDGE) {
19628  // An edge is intersected with the segment. Try to flip it.
19629  success = removeedgebyflips(&searchtet, &fc);
19630  }
19631 
19632  split = 0;
19633  for (i = 0; i < caveencseglist->objects; i++) {
19634  paryseg = (face *) fastlookup(caveencseglist, i);
19635  suninfect(*paryseg);
19636  // Calculate the shortest edge between the two lines.
19637  pc = sorg(*paryseg);
19638  pd = sdest(*paryseg);
19639  tp = tq = 0;
19640  if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
19641  // Does the shortest edge lie between the two segments?
19642  // Round tp and tq.
19643  if ((tp > 0) && (tq < 1)) {
19644  if (tp < 0.5) {
19645  if (tp < (b->epsilon * 1e+3)) tp = 0.0;
19646  } else {
19647  if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
19648  }
19649  }
19650  if ((tp <= 0) || (tp >= 1)) continue;
19651  if ((tq > 0) && (tq < 1)) {
19652  if (tq < 0.5) {
19653  if (tq < (b->epsilon * 1e+3)) tq = 0.0;
19654  } else {
19655  if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
19656  }
19657  }
19658  if ((tq <= 0) || (tq >= 1)) continue;
19659  // It is a valid shortest edge. Calculate its length.
19660  len = distance(P, Q);
19661  if (split == 0) {
19662  smlen = len;
19663  split = tp;
19664  split_q = tq;
19665  candseg = *paryseg;
19666  } else {
19667  if (len < smlen) {
19668  smlen = len;
19669  split = tp;
19670  split_q = tq;
19671  candseg = *paryseg;
19672  }
19673  }
19674  }
19675  }
19676 
19677  caveencseglist->restart();
19678  b->fliplinklevel = bak_fliplinklevel;
19679 
19680  if (split == 0) {
19681  // Found no crossing segment.
19682  return 0;
19683  }
19684 
19685  face splitsh;
19686  face splitseg;
19687  point steinerpt, *parypt;
19688  insertvertexflags ivf;
19689 
19690  if (b->addsteiner_algo == 1) {
19691  // Split the segment at the closest point to a near segment.
19692  makepoint(&steinerpt, FREESEGVERTEX);
19693  for (i = 0; i < 3; i++) {
19694  steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19695  }
19696  } else { // b->addsteiner_algo == 2
19697  for (i = 0; i < 3; i++) {
19698  P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19699  }
19700  pc = sorg(candseg);
19701  pd = sdest(candseg);
19702  for (i = 0; i < 3; i++) {
19703  Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
19704  }
19705  makepoint(&steinerpt, FREEVOLVERTEX);
19706  for (i = 0; i < 3; i++) {
19707  steinerpt[i] = 0.5 * (P[i] + Q[i]);
19708  }
19709  }
19710 
19711  // We need to locate the point. Start searching from 'searchtet'.
19712  if (split < 0.5) {
19713  point2tetorg(startpt, searchtet);
19714  } else {
19715  point2tetorg(endpt, searchtet);
19716  }
19717  if (b->addsteiner_algo == 1) {
19718  splitseg = *misseg;
19719  spivot(*misseg, splitsh);
19720  } else {
19721  splitsh.sh = NULL;
19722  splitseg.sh = NULL;
19723  }
19724  ivf.iloc = (int) OUTSIDE;
19725  ivf.bowywat = 1;
19726  ivf.lawson = 0;
19727  ivf.rejflag = 0;
19728  ivf.chkencflag = 0;
19729  ivf.sloc = (int) ONEDGE;
19730  ivf.sbowywat = 1;
19731  ivf.splitbdflag = 0;
19732  ivf.validflag = 1;
19733  ivf.respectbdflag = 1;
19734  ivf.assignmeshsize = b->metric;
19735 
19736  if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
19737  pointdealloc(steinerpt);
19738  return 0;
19739  }
19740 
19741  if (b->addsteiner_algo == 1) {
19742  // Save this Steiner point (for removal).
19743  // Re-use the array 'subvertstack'.
19744  subvertstack->newindex((void **) &parypt);
19745  *parypt = steinerpt;
19746  st_segref_count++;
19747  } else { // b->addsteiner_algo == 2
19748  // Queue the segment for recovery.
19749  subsegstack->newindex((void **) &paryseg);
19750  *paryseg = *misseg;
19751  st_volref_count++;
19752  }
19753  if (steinerleft > 0) steinerleft--;
19754 
19755  return 1;
19756 }
19757 
19759 // //
19760 // addsteiner4recoversegment() Add a Steiner point for recovering a seg. //
19761 // //
19763 
19764 int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
19765 {
19766  triface *abtets, searchtet, spintet;
19767  face splitsh;
19768  face *paryseg;
19769  point startpt, endpt;
19770  point pa, pb, pd, steinerpt, *parypt;
19771  enum interresult dir;
19772  insertvertexflags ivf;
19773  int types[2], poss[4];
19774  int n, endi, success;
19775  int t1ver;
19776  int i;
19777 
19778  startpt = sorg(*misseg);
19779  if (pointtype(startpt) == FREESEGVERTEX) {
19780  sesymself(*misseg);
19781  startpt = sorg(*misseg);
19782  }
19783  endpt = sdest(*misseg);
19784 
19785  // Try to recover the edge by adding Steiner points.
19786  point2tetorg(startpt, searchtet);
19787  dir = finddirection(&searchtet, endpt);
19788  enextself(searchtet);
19789 
19790  if (dir == ACROSSFACE) {
19791  // The segment is crossing at least 3 faces. Find the common edge of
19792  // the first 3 crossing faces.
19793  esymself(searchtet);
19794  fsym(searchtet, spintet);
19795  pd = oppo(spintet);
19796  for (i = 0; i < 3; i++) {
19797  pa = org(spintet);
19798  pb = dest(spintet);
19799  if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
19800  break; // Found the edge.
19801  }
19802  enextself(spintet);
19803  eprevself(searchtet);
19804  }
19805  esymself(searchtet);
19806  }
19807 
19808  spintet = searchtet;
19809  n = 0; endi = -1;
19810  while (1) {
19811  // Check if the endpt appears in the star.
19812  if (apex(spintet) == endpt) {
19813  endi = n; // Remember the position of endpt.
19814  }
19815  n++; // Count a tet in the star.
19816  fnextself(spintet);
19817  if (spintet.tet == searchtet.tet) break;
19818  }
19819 
19820  if (endi > 0) {
19821  // endpt is also in the edge star
19822  // Get all tets in the edge star.
19823  abtets = new triface[n];
19824  spintet = searchtet;
19825  for (i = 0; i < n; i++) {
19826  abtets[i] = spintet;
19827  fnextself(spintet);
19828  }
19829 
19830  success = 0;
19831 
19832  if (dir == ACROSSFACE) {
19833  // Find a Steiner points inside the polyhedron.
19834  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19835  success = 1;
19836  }
19837  } else if (dir == ACROSSEDGE) {
19838  // PLC check.
19839  if (issubseg(searchtet)) {
19840  terminatetetgen(this, 2);
19841  }
19842  if (n > 4) {
19843  // In this case, 'abtets' is separated by the plane (containing the
19844  // two intersecting edges) into two parts, P1 and P2, where P1
19845  // consists of 'endi' tets: abtets[0], abtets[1], ...,
19846  // abtets[endi-1], and P2 consists of 'n - endi' tets:
19847  // abtets[endi], abtets[endi+1], abtets[n-1].
19848  if (endi > 2) { // P1
19849  // There are at least 3 tets in the first part.
19850  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19851  success++;
19852  }
19853  }
19854  if ((n - endi) > 2) { // P2
19855  // There are at least 3 tets in the first part.
19856  if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
19857  success++;
19858  }
19859  }
19860  } else {
19861  // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
19862  // However, there will be invalid tets (either zero or negtive
19863  // volume). Otherwise, [c,d] should already be recovered by the
19864  // recoveredge() function.
19865  terminatetetgen(this, 2);
19866  }
19867  } else {
19868  terminatetetgen(this, 2);
19869  }
19870 
19871  delete [] abtets;
19872 
19873  if (success) {
19874  // Add the missing segment back to the recovering list.
19875  subsegstack->newindex((void **) &paryseg);
19876  *paryseg = *misseg;
19877  return 1;
19878  }
19879  } // if (endi > 0)
19880 
19881  if (!splitsegflag) {
19882  return 0;
19883  }
19884 
19885  if (b->verbose > 2) {
19886  printf(" Splitting segment (%d, %d)\n", pointmark(startpt),
19887  pointmark(endpt));
19888  }
19889  steinerpt = NULL;
19890 
19891  if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
19892  if (add_steinerpt_in_segment(misseg, 3)) {
19893  return 1;
19894  }
19895  sesymself(*misseg);
19896  if (add_steinerpt_in_segment(misseg, 3)) {
19897  return 1;
19898  }
19899  sesymself(*misseg);
19900  }
19901 
19902 
19903 
19904 
19905  if (steinerpt == NULL) {
19906  // Split the segment at its midpoint.
19907  makepoint(&steinerpt, FREESEGVERTEX);
19908  for (i = 0; i < 3; i++) {
19909  steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
19910  }
19911 
19912  // We need to locate the point.
19913  spivot(*misseg, splitsh);
19914  ivf.iloc = (int) OUTSIDE;
19915  ivf.bowywat = 1;
19916  ivf.lawson = 0;
19917  ivf.rejflag = 0;
19918  ivf.chkencflag = 0;
19919  ivf.sloc = (int) ONEDGE;
19920  ivf.sbowywat = 1;
19921  ivf.splitbdflag = 0;
19922  ivf.validflag = 1;
19923  ivf.respectbdflag = 1;
19924  ivf.assignmeshsize = b->metric;
19925  if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
19926  terminatetetgen(this, 2);
19927  }
19928  } // if (endi > 0)
19929 
19930  // Save this Steiner point (for removal).
19931  // Re-use the array 'subvertstack'.
19932  subvertstack->newindex((void **) &parypt);
19933  *parypt = steinerpt;
19934 
19935  st_segref_count++;
19936  if (steinerleft > 0) steinerleft--;
19937 
19938  return 1;
19939 }
19940 
19942 // //
19943 // recoversegments() Recover all segments. //
19944 // //
19945 // All segments need to be recovered are in 'subsegstack'. //
19946 // //
19947 // This routine first tries to recover each segment by only using flips. If //
19948 // no flip is possible, and the flag 'steinerflag' is set, it then tries to //
19949 // insert Steiner points near or in the segment. //
19950 // //
19952 
19953 int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
19954  int steinerflag)
19955 {
19956  triface searchtet, spintet;
19957  face sseg, *paryseg;
19958  point startpt, endpt;
19959  int success;
19960  int t1ver;
19961 
19962  long bak_inpoly_count = st_volref_count;
19963  long bak_segref_count = st_segref_count;
19964 
19965  if (b->verbose > 1) {
19966  printf(" Recover segments [%s level = %2d] #: %ld.\n",
19967  (b->fliplinklevel > 0) ? "fixed" : "auto",
19968  (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
19969  subsegstack->objects);
19970  }
19971 
19972  // Loop until 'subsegstack' is empty.
19973  while (subsegstack->objects > 0l) {
19974  // seglist is used as a stack.
19975  subsegstack->objects--;
19976  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
19977  sseg = *paryseg;
19978 
19979  // Check if this segment has been recovered.
19980  sstpivot1(sseg, searchtet);
19981  if (searchtet.tet != NULL) {
19982  continue; // Not a missing segment.
19983  }
19984 
19985  startpt = sorg(sseg);
19986  endpt = sdest(sseg);
19987 
19988  if (b->verbose > 2) {
19989  printf(" Recover segment (%d, %d).\n", pointmark(startpt),
19990  pointmark(endpt));
19991  }
19992 
19993  success = 0;
19994 
19995  if (recoveredgebyflips(startpt, endpt, &sseg, &searchtet, 0)) {
19996  success = 1;
19997  } else {
19998  // Try to recover it from the other direction.
19999  if (recoveredgebyflips(endpt, startpt, &sseg, &searchtet, 0)) {
20000  success = 1;
20001  }
20002  }
20003 
20004  if (!success && fullsearch) {
20005  if (recoveredgebyflips(startpt, endpt, &sseg, &searchtet, fullsearch)) {
20006  success = 1;
20007  }
20008  }
20009 
20010  if (success) {
20011  // Segment is recovered. Insert it.
20012  // Let the segment remember an adjacent tet.
20013  sstbond1(sseg, searchtet);
20014  // Bond the segment to all tets containing it.
20015  spintet = searchtet;
20016  do {
20017  tssbond1(spintet, sseg);
20018  fnextself(spintet);
20019  } while (spintet.tet != searchtet.tet);
20020  } else {
20021  if (steinerflag > 0) {
20022  // Try to recover the segment but do not split it.
20023  if (addsteiner4recoversegment(&sseg, 0)) {
20024  success = 1;
20025  }
20026  if (!success && (steinerflag > 1)) {
20027  // Split the segment.
20028  addsteiner4recoversegment(&sseg, 1);
20029  success = 1;
20030  }
20031  }
20032  if (!success) {
20033  if (misseglist != NULL) {
20034  // Save this segment.
20035  misseglist->newindex((void **) &paryseg);
20036  *paryseg = sseg;
20037  }
20038  }
20039  }
20040 
20041  } // while (subsegstack->objects > 0l)
20042 
20043  if (steinerflag) {
20044  if (b->verbose > 1) {
20045  // Report the number of added Steiner points.
20046  if (st_volref_count > bak_inpoly_count) {
20047  printf(" Add %ld Steiner points in volume.\n",
20048  st_volref_count - bak_inpoly_count);
20049  }
20050  if (st_segref_count > bak_segref_count) {
20051  printf(" Add %ld Steiner points in segments.\n",
20052  st_segref_count - bak_segref_count);
20053  }
20054  }
20055  }
20056 
20057  return 0;
20058 }
20059 
20061 // //
20062 // recoverfacebyflips() Recover a face by flips. //
20063 // //
20064 // 'pa', 'pb', and 'pc' are the three vertices of this face. This routine //
20065 // tries to recover it in the tetrahedral mesh. It is assumed that the three //
20066 // edges, i.e., pa->pb, pb->pc, and pc->pa all exist. //
20067 // //
20068 // If the face is recovered, it is returned by 'searchtet'. //
20069 // //
20070 // If 'searchsh' is not NULL, it is a subface to be recovered. Its vertices //
20071 // must be pa, pb, and pc. It is mainly used to check self-intersections. //
20072 // Another use of this subface is to split it when a Steiner point is found //
20073 // inside this subface. //
20074 // //
20076 
20077 int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
20078  face *searchsh, triface* searchtet)
20079 {
20080  triface spintet, flipedge;
20081  point pd, pe;
20082  flipconstraints fc;
20083  int types[2], poss[4], intflag;
20084  int success;
20085  int t1ver;
20086  int i, j;
20087 
20088 
20089  fc.fac[0] = pa;
20090  fc.fac[1] = pb;
20091  fc.fac[2] = pc;
20092  fc.checkflipeligibility = 1;
20093  success = 0;
20094 
20095  for (i = 0; i < 3 && !success; i++) {
20096  while (1) {
20097  // Get a tet containing the edge [a,b].
20098  point2tetorg(fc.fac[i], *searchtet);
20099  finddirection(searchtet, fc.fac[(i+1)%3]);
20100  // Search the face [a,b,c]
20101  spintet = *searchtet;
20102  while (1) {
20103  if (apex(spintet) == fc.fac[(i+2)%3]) {
20104  // Found the face.
20105  *searchtet = spintet;
20106  // Return the face [a,b,c].
20107  for (j = i; j > 0; j--) {
20108  eprevself(*searchtet);
20109  }
20110  success = 1;
20111  break;
20112  }
20113  fnextself(spintet);
20114  if (spintet.tet == searchtet->tet) break;
20115  } // while (1)
20116  if (success) break;
20117  // The face is missing. Try to recover it.
20118  flipedge.tet = NULL;
20119  // Find a crossing edge of this face.
20120  spintet = *searchtet;
20121  while (1) {
20122  pd = apex(spintet);
20123  pe = oppo(spintet);
20124  if ((pd != dummypoint) && (pe != dummypoint)) {
20125  // Check if [d,e] intersects [a,b,c]
20126  intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
20127  if (intflag > 0) {
20128  // By the assumption that all edges of the face exist, they can
20129  // only intersect at a single point.
20130  if (intflag == 2) {
20131  // Go to the edge [d,e].
20132  edestoppo(spintet, flipedge); // [d,e,a,b]
20133  if (searchsh != NULL) {
20134  // Check the intersection type.
20135  if ((types[0] == (int) ACROSSFACE) ||
20136  (types[0] == (int) ACROSSEDGE)) {
20137  // Check if [e,d] is a segment.
20138  if (issubseg(flipedge)) {
20139  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
20140  intflag, types, poss);
20141  } else {
20142  // Check if [e,d] is an edge of a subface.
20143  triface chkface = flipedge;
20144  while (1) {
20145  if (issubface(chkface)) break;
20146  fsymself(chkface);
20147  if (chkface.tet == flipedge.tet) break;
20148  }
20149  if (issubface(chkface)) {
20150  // Two subfaces are intersecting.
20151  return report_selfint_face(pa, pb, pc,searchsh,&chkface,
20152  intflag, types, poss);
20153  }
20154  }
20155  } else if (types[0] == TOUCHFACE) {
20156  // This is possible when a Steiner point was added on it.
20157  point touchpt, *parypt;
20158  if (poss[1] == 0) {
20159  touchpt = pd; // pd is a coplanar vertex.
20160  } else {
20161  touchpt = pe; // pe is a coplanar vertex.
20162  }
20163  if (pointtype(touchpt) == FREEVOLVERTEX) {
20164  // A volume Steiner point was added in this subface.
20165  // Split this subface by this point.
20166  face checksh, *parysh;
20167  int siloc = (int) ONFACE;
20168  int sbowat = 0; // Only split this subface. A 1-to-3 flip.
20169  setpointtype(touchpt, FREEFACETVERTEX);
20170  sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
20171  st_volref_count--;
20172  st_facref_count++;
20173  // Queue this vertex for removal.
20174  subvertstack->newindex((void **) &parypt);
20175  *parypt = touchpt;
20176  // Queue new subfaces for recovery.
20177  // Put all new subfaces into stack for recovery.
20178  for (i = 0; i < caveshbdlist->objects; i++) {
20179  // Get an old subface at edge [a, b].
20180  parysh = (face *) fastlookup(caveshbdlist, i);
20181  spivot(*parysh, checksh); // The new subface [a, b, p].
20182  // Do not recover a deleted new face (degenerated).
20183  if (checksh.sh[3] != NULL) {
20184  subfacstack->newindex((void **) &parysh);
20185  *parysh = checksh;
20186  }
20187  }
20188  // Delete the old subfaces in sC(p).
20189  for (i = 0; i < caveshlist->objects; i++) {
20190  parysh = (face *) fastlookup(caveshlist, i);
20191  shellfacedealloc(subfaces, parysh->sh);
20192  }
20193  // Clear working lists.
20194  caveshlist->restart();
20195  caveshbdlist->restart();
20196  cavesegshlist->restart();
20197  // We can return this function.
20198  searchsh->sh = NULL; // It has been split.
20199  return 1;
20200  } else {
20201  // Other cases may be due to a bug or a PLC error.
20202  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
20203  intflag, types, poss);
20204  }
20205  } else {
20206  // The other intersection types: ACROSSVERT, TOUCHEDGE,
20207  // SHAREVERTEX should not be possible or due to a PLC error.
20208  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
20209  intflag, types, poss);
20210  }
20211  } // if (searchsh != NULL)
20212  } else { // intflag == 4. Coplanar case.
20213  terminatetetgen(this, 2);
20214  }
20215  break;
20216  } // if (intflag > 0)
20217  }
20218  fnextself(spintet);
20219  if (spintet.tet == searchtet->tet) {
20220  terminatetetgen(this, 2);
20221  }
20222  } // while (1)
20223  // Try to flip the edge [d,e].
20224  if (removeedgebyflips(&flipedge, &fc) == 2) {
20225  // A crossing edge is removed.
20226  continue;
20227  }
20228  break;
20229  } // while (1)
20230  } // i
20231 
20232  return success;
20233 }
20234 
20236 // //
20237 // recoversubfaces() Recover all subfaces. //
20238 // //
20240 
20241 int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
20242 {
20243  triface searchtet, neightet, spintet;
20244  face searchsh, neighsh, neineish, *parysh;
20245  face bdsegs[3];
20246  point startpt, endpt, apexpt, *parypt;
20247  point steinerpt;
20248  insertvertexflags ivf;
20249  int success;
20250  int t1ver;
20251  int i, j;
20252 
20253  if (b->verbose > 1) {
20254  printf(" Recover subfaces [%s level = %2d] #: %ld.\n",
20255  (b->fliplinklevel > 0) ? "fixed" : "auto",
20256  (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
20257  subfacstack->objects);
20258  }
20259 
20260  // Loop until 'subfacstack' is empty.
20261  while (subfacstack->objects > 0l) {
20262 
20263  subfacstack->objects--;
20264  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
20265  searchsh = *parysh;
20266 
20267  if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
20268 
20269  stpivot(searchsh, neightet);
20270  if (neightet.tet != NULL) continue; // Skip a recovered subface.
20271 
20272 
20273  if (b->verbose > 2) {
20274  printf(" Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
20275  pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
20276  }
20277 
20278  // The three edges of the face need to be existed first.
20279  for (i = 0; i < 3; i++) {
20280  sspivot(searchsh, bdsegs[i]);
20281  if (bdsegs[i].sh != NULL) {
20282  // The segment must exist.
20283  sstpivot1(bdsegs[i], searchtet);
20284  if (searchtet.tet == NULL) {
20285  terminatetetgen(this, 2);
20286  }
20287  } else {
20288  // This edge is not a segment (due to a Steiner point).
20289  // Check whether it exists or not.
20290  success = 0;
20291  startpt = sorg(searchsh);
20292  endpt = sdest(searchsh);
20293  point2tetorg(startpt, searchtet);
20294  finddirection(&searchtet, endpt);
20295  if (dest(searchtet) == endpt) {
20296  success = 1;
20297  } else {
20298  // The edge is missing. Try to recover it.
20299  if (recoveredgebyflips(startpt, endpt, &searchsh, &searchtet, 0)) {
20300  success = 1;
20301  } else {
20302  if (recoveredgebyflips(endpt, startpt, &searchsh, &searchtet, 0)) {
20303  success = 1;
20304  }
20305  }
20306  }
20307  if (success) {
20308  // Insert a temporary segment to protect this edge.
20309  makeshellface(subsegs, &(bdsegs[i]));
20310  setshvertices(bdsegs[i], startpt, endpt, NULL);
20311  smarktest2(bdsegs[i]); // It's a temporary segment.
20312  // Insert this segment into surface mesh.
20313  ssbond(searchsh, bdsegs[i]);
20314  spivot(searchsh, neighsh);
20315  if (neighsh.sh != NULL) {
20316  ssbond(neighsh, bdsegs[i]);
20317  }
20318  // Insert this segment into tetrahedralization.
20319  sstbond1(bdsegs[i], searchtet);
20320  // Bond the segment to all tets containing it.
20321  spintet = searchtet;
20322  do {
20323  tssbond1(spintet, bdsegs[i]);
20324  fnextself(spintet);
20325  } while (spintet.tet != searchtet.tet);
20326  } else {
20327  // An edge of this subface is missing. Can't recover this subface.
20328  // Delete any temporary segment that has been created.
20329  for (j = (i - 1); j >= 0; j--) {
20330  if (smarktest2ed(bdsegs[j])) {
20331  spivot(bdsegs[j], neineish);
20332  ssdissolve(neineish);
20333  spivot(neineish, neighsh);
20334  if (neighsh.sh != NULL) {
20335  ssdissolve(neighsh);
20336  }
20337  sstpivot1(bdsegs[j], searchtet);
20338  spintet = searchtet;
20339  while (1) {
20340  tssdissolve1(spintet);
20341  fnextself(spintet);
20342  if (spintet.tet == searchtet.tet) break;
20343  }
20344  shellfacedealloc(subsegs, bdsegs[j].sh);
20345  }
20346  } // j
20347  if (steinerflag) {
20348  // Add a Steiner point at the midpoint of this edge.
20349  if (b->verbose > 2) {
20350  printf(" Add a Steiner point in subedge (%d, %d).\n",
20351  pointmark(startpt), pointmark(endpt));
20352  }
20353  makepoint(&steinerpt, FREEFACETVERTEX);
20354  for (j = 0; j < 3; j++) {
20355  steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
20356  }
20357 
20358  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
20359  ivf.iloc = (int) OUTSIDE; // Need point location.
20360  ivf.bowywat = 1;
20361  ivf.lawson = 0;
20362  ivf.rejflag = 0;
20363  ivf.chkencflag = 0;
20364  ivf.sloc = (int) ONEDGE;
20365  ivf.sbowywat = 1; // Allow flips in facet.
20366  ivf.splitbdflag = 0;
20367  ivf.validflag = 1;
20368  ivf.respectbdflag = 1;
20369  ivf.assignmeshsize = b->metric;
20370  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
20371  terminatetetgen(this, 2);
20372  }
20373  // Save this Steiner point (for removal).
20374  // Re-use the array 'subvertstack'.
20375  subvertstack->newindex((void **) &parypt);
20376  *parypt = steinerpt;
20377 
20378  st_facref_count++;
20379  if (steinerleft > 0) steinerleft--;
20380  } // if (steinerflag)
20381  break;
20382  }
20383  }
20384  senextself(searchsh);
20385  } // i
20386 
20387  if (i == 3) {
20388  // Recover the subface.
20389  startpt = sorg(searchsh);
20390  endpt = sdest(searchsh);
20391  apexpt = sapex(searchsh);
20392 
20393  success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
20394 
20395  // Delete any temporary segment that has been created.
20396  for (j = 0; j < 3; j++) {
20397  if (smarktest2ed(bdsegs[j])) {
20398  spivot(bdsegs[j], neineish);
20399  ssdissolve(neineish);
20400  spivot(neineish, neighsh);
20401  if (neighsh.sh != NULL) {
20402  ssdissolve(neighsh);
20403  }
20404  sstpivot1(bdsegs[j], neightet);
20405  spintet = neightet;
20406  while (1) {
20407  tssdissolve1(spintet);
20408  fnextself(spintet);
20409  if (spintet.tet == neightet.tet) break;
20410  }
20411  shellfacedealloc(subsegs, bdsegs[j].sh);
20412  }
20413  } // j
20414 
20415  if (success) {
20416  if (searchsh.sh != NULL) {
20417  // Face is recovered. Insert it.
20418  tsbond(searchtet, searchsh);
20419  fsymself(searchtet);
20420  sesymself(searchsh);
20421  tsbond(searchtet, searchsh);
20422  }
20423  } else {
20424  if (steinerflag) {
20425  // Add a Steiner point at the barycenter of this subface.
20426  if (b->verbose > 2) {
20427  printf(" Add a Steiner point in subface (%d, %d, %d).\n",
20428  pointmark(startpt), pointmark(endpt), pointmark(apexpt));
20429  }
20430  makepoint(&steinerpt, FREEFACETVERTEX);
20431  for (j = 0; j < 3; j++) {
20432  steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
20433  }
20434 
20435  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
20436  ivf.iloc = (int) OUTSIDE; // Need point location.
20437  ivf.bowywat = 1;
20438  ivf.lawson = 0;
20439  ivf.rejflag = 0;
20440  ivf.chkencflag = 0;
20441  ivf.sloc = (int) ONFACE;
20442  ivf.sbowywat = 1; // Allow flips in facet.
20443  ivf.splitbdflag = 0;
20444  ivf.validflag = 1;
20445  ivf.respectbdflag = 1;
20446  ivf.assignmeshsize = b->metric;
20447  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
20448  terminatetetgen(this, 2);
20449  }
20450  // Save this Steiner point (for removal).
20451  // Re-use the array 'subvertstack'.
20452  subvertstack->newindex((void **) &parypt);
20453  *parypt = steinerpt;
20454 
20455  st_facref_count++;
20456  if (steinerleft > 0) steinerleft--;
20457  } // if (steinerflag)
20458  }
20459  } else {
20460  success = 0;
20461  }
20462 
20463  if (!success) {
20464  if (misshlist != NULL) {
20465  // Save this subface.
20466  misshlist->newindex((void **) &parysh);
20467  *parysh = searchsh;
20468  }
20469  }
20470 
20471  } // while (subfacstack->objects > 0l)
20472 
20473  return 0;
20474 }
20475 
20477 // //
20478 // getvertexstar() Return the star of a vertex. //
20479 // //
20480 // If the flag 'fullstar' is set, return the complete star of this vertex. //
20481 // Otherwise, only a part of the star which is bounded by facets is returned.//
20482 // //
20483 // 'tetlist' returns the list of tets in the star of the vertex 'searchpt'. //
20484 // Every tet in 'tetlist' is at the face opposing to 'searchpt'. //
20485 // //
20486 // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
20487 // //
20488 // 'shlist' returns the list of subfaces in the star. Each subface must face //
20489 // to the interior of this star. //
20490 // //
20492 
20493 int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
20494  arraypool* vertlist, arraypool* shlist)
20495 {
20496  triface searchtet, neightet, *parytet;
20497  face checksh, *parysh;
20498  point pt, *parypt;
20499  int collectflag;
20500  int t1ver;
20501  int i, j;
20502 
20503  point2tetorg(searchpt, searchtet);
20504 
20505  // Go to the opposite face (the link face) of the vertex.
20506  enextesymself(searchtet);
20507  //assert(oppo(searchtet) == searchpt);
20508  infect(searchtet); // Collect this tet (link face).
20509  tetlist->newindex((void **) &parytet);
20510  *parytet = searchtet;
20511  if (vertlist != NULL) {
20512  // Collect three (link) vertices.
20513  j = (searchtet.ver & 3); // The current vertex index.
20514  for (i = 1; i < 4; i++) {
20515  pt = (point) searchtet.tet[4 + ((j + i) % 4)];
20516  pinfect(pt);
20517  vertlist->newindex((void **) &parypt);
20518  *parypt = pt;
20519  }
20520  }
20521 
20522  collectflag = 1;
20523  esym(searchtet, neightet);
20524  if (issubface(neightet)) {
20525  if (shlist != NULL) {
20526  tspivot(neightet, checksh);
20527  if (!sinfected(checksh)) {
20528  // Collect this subface (link edge).
20529  sinfected(checksh);
20530  shlist->newindex((void **) &parysh);
20531  *parysh = checksh;
20532  }
20533  }
20534  if (!fullstar) {
20535  collectflag = 0;
20536  }
20537  }
20538  if (collectflag) {
20539  fsymself(neightet); // Goto the adj tet of this face.
20540  esymself(neightet); // Goto the oppo face of this vertex.
20541  // assert(oppo(neightet) == searchpt);
20542  infect(neightet); // Collect this tet (link face).
20543  tetlist->newindex((void **) &parytet);
20544  *parytet = neightet;
20545  if (vertlist != NULL) {
20546  // Collect its apex.
20547  pt = apex(neightet);
20548  pinfect(pt);
20549  vertlist->newindex((void **) &parypt);
20550  *parypt = pt;
20551  }
20552  } // if (collectflag)
20553 
20554  // Continue to collect all tets in the star.
20555  for (i = 0; i < tetlist->objects; i++) {
20556  searchtet = * (triface *) fastlookup(tetlist, i);
20557  // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
20558  // tet at the current edge is already collected.
20559  // Check the neighbors at the other two edges of this face.
20560  for (j = 0; j < 2; j++) {
20561  collectflag = 1;
20562  enextself(searchtet);
20563  esym(searchtet, neightet);
20564  if (issubface(neightet)) {
20565  if (shlist != NULL) {
20566  tspivot(neightet, checksh);
20567  if (!sinfected(checksh)) {
20568  // Collect this subface (link edge).
20569  sinfected(checksh);
20570  shlist->newindex((void **) &parysh);
20571  *parysh = checksh;
20572  }
20573  }
20574  if (!fullstar) {
20575  collectflag = 0;
20576  }
20577  }
20578  if (collectflag) {
20579  fsymself(neightet);
20580  if (!infected(neightet)) {
20581  esymself(neightet); // Go to the face opposite to 'searchpt'.
20582  infect(neightet);
20583  tetlist->newindex((void **) &parytet);
20584  *parytet = neightet;
20585  if (vertlist != NULL) {
20586  // Check if a vertex is collected.
20587  pt = apex(neightet);
20588  if (!pinfected(pt)) {
20589  pinfect(pt);
20590  vertlist->newindex((void **) &parypt);
20591  *parypt = pt;
20592  }
20593  }
20594  } // if (!infected(neightet))
20595  } // if (collectflag)
20596  } // j
20597  } // i
20598 
20599 
20600  // Uninfect the list of tets and vertices.
20601  for (i = 0; i < tetlist->objects; i++) {
20602  parytet = (triface *) fastlookup(tetlist, i);
20603  uninfect(*parytet);
20604  }
20605 
20606  if (vertlist != NULL) {
20607  for (i = 0; i < vertlist->objects; i++) {
20608  parypt = (point *) fastlookup(vertlist, i);
20609  puninfect(*parypt);
20610  }
20611  }
20612 
20613  if (shlist != NULL) {
20614  for (i = 0; i < shlist->objects; i++) {
20615  parysh = (face *) fastlookup(shlist, i);
20616  suninfect(*parysh);
20617  }
20618  }
20619 
20620  return (int) tetlist->objects;
20621 }
20622 
20624 // //
20625 // getedge() Get a tetrahedron having the two endpoints. //
20626 // //
20627 // The method here is to search the second vertex in the link faces of the //
20628 // first vertex. The global array 'cavetetlist' is re-used for searching. //
20629 // //
20630 // This function is used for the case when the mesh is non-convex. Otherwise,//
20631 // the function finddirection() should be faster than this. //
20632 // //
20634 
20635 int tetgenmesh::getedge(point e1, point e2, triface *tedge)
20636 {
20637  triface searchtet, neightet, *parytet;
20638  point pt;
20639  int done;
20640  int i, j;
20641 
20642  if (b->verbose > 2) {
20643  printf(" Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
20644  }
20645 
20646  // Quickly check if 'tedge' is just this edge.
20647  if (!isdeadtet(*tedge)) {
20648  if (org(*tedge) == e1) {
20649  if (dest(*tedge) == e2) {
20650  return 1;
20651  }
20652  } else if (org(*tedge) == e2) {
20653  if (dest(*tedge) == e1) {
20654  esymself(*tedge);
20655  return 1;
20656  }
20657  }
20658  }
20659 
20660  // Search for the edge [e1, e2].
20661  point2tetorg(e1, *tedge);
20662  finddirection(tedge, e2);
20663  if (dest(*tedge) == e2) {
20664  return 1;
20665  } else {
20666  // Search for the edge [e2, e1].
20667  point2tetorg(e2, *tedge);
20668  finddirection(tedge, e1);
20669  if (dest(*tedge) == e1) {
20670  esymself(*tedge);
20671  return 1;
20672  }
20673  }
20674 
20675 
20676  // Go to the link face of e1.
20677  point2tetorg(e1, searchtet);
20678  enextesymself(searchtet);
20679  arraypool *tetlist = cavebdrylist;
20680 
20681  // Search e2.
20682  for (i = 0; i < 3; i++) {
20683  pt = apex(searchtet);
20684  if (pt == e2) {
20685  // Found. 'searchtet' is [#,#,e2,e1].
20686  eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
20687  return 1;
20688  }
20689  enextself(searchtet);
20690  }
20691 
20692  // Get the adjacent link face at 'searchtet'.
20693  fnext(searchtet, neightet);
20694  esymself(neightet);
20695  // assert(oppo(neightet) == e1);
20696  pt = apex(neightet);
20697  if (pt == e2) {
20698  // Found. 'neightet' is [#,#,e2,e1].
20699  eorgoppo(neightet, *tedge); // [e1,e2,#,#].
20700  return 1;
20701  }
20702 
20703  // Continue searching in the link face of e1.
20704  infect(searchtet);
20705  tetlist->newindex((void **) &parytet);
20706  *parytet = searchtet;
20707  infect(neightet);
20708  tetlist->newindex((void **) &parytet);
20709  *parytet = neightet;
20710 
20711  done = 0;
20712 
20713  for (i = 0; (i < tetlist->objects) && !done; i++) {
20714  parytet = (triface *) fastlookup(tetlist, i);
20715  searchtet = *parytet;
20716  for (j = 0; (j < 2) && !done; j++) {
20717  enextself(searchtet);
20718  fnext(searchtet, neightet);
20719  if (!infected(neightet)) {
20720  esymself(neightet);
20721  pt = apex(neightet);
20722  if (pt == e2) {
20723  // Found. 'neightet' is [#,#,e2,e1].
20724  eorgoppo(neightet, *tedge);
20725  done = 1;
20726  } else {
20727  infect(neightet);
20728  tetlist->newindex((void **) &parytet);
20729  *parytet = neightet;
20730  }
20731  }
20732  } // j
20733  } // i
20734 
20735  // Uninfect the list of visited tets.
20736  for (i = 0; i < tetlist->objects; i++) {
20737  parytet = (triface *) fastlookup(tetlist, i);
20738  uninfect(*parytet);
20739  }
20740  tetlist->restart();
20741 
20742  return done;
20743 }
20744 
20746 // //
20747 // reduceedgesatvertex() Reduce the number of edges at a given vertex. //
20748 // //
20749 // 'endptlist' contains the endpoints of edges connecting at the vertex. //
20750 // //
20752 
20753 int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
20754 {
20755  triface searchtet;
20756  point *pendpt, *parypt;
20757  enum interresult dir;
20758  flipconstraints fc;
20759  int reduceflag;
20760  int count;
20761  int n, i, j;
20762 
20763 
20764  fc.remvert = startpt;
20765  fc.checkflipeligibility = 1;
20766 
20767  while (1) {
20768 
20769  count = 0;
20770 
20771  for (i = 0; i < endptlist->objects; i++) {
20772  pendpt = (point *) fastlookup(endptlist, i);
20773  if (*pendpt == dummypoint) {
20774  continue; // Do not reduce a virtual edge.
20775  }
20776  reduceflag = 0;
20777  // Find the edge.
20778  if (nonconvex) {
20779  if (getedge(startpt, *pendpt, &searchtet)) {
20780  dir = ACROSSVERT;
20781  } else {
20782  // The edge does not exist (was flipped).
20783  dir = INTERSECT;
20784  }
20785  } else {
20786  point2tetorg(startpt, searchtet);
20787  dir = finddirection(&searchtet, *pendpt);
20788  }
20789  if (dir == ACROSSVERT) {
20790  if (dest(searchtet) == *pendpt) {
20791  // Do not flip a segment.
20792  if (!issubseg(searchtet)) {
20793  n = removeedgebyflips(&searchtet, &fc);
20794  if (n == 2) {
20795  reduceflag = 1;
20796  }
20797  }
20798  }
20799  } else {
20800  // The edge has been flipped.
20801  reduceflag = 1;
20802  }
20803  if (reduceflag) {
20804  count++;
20805  // Move the last vertex into this slot.
20806  j = endptlist->objects - 1;
20807  parypt = (point *) fastlookup(endptlist, j);
20808  *pendpt = *parypt;
20809  endptlist->objects--;
20810  i--;
20811  }
20812  } // i
20813 
20814  if (count == 0) {
20815  // No edge is reduced.
20816  break;
20817  }
20818 
20819  } // while (1)
20820 
20821  return (int) endptlist->objects;
20822 }
20823 
20825 // //
20826 // removevertexbyflips() Remove a vertex by flips. //
20827 // //
20828 // This routine attempts to remove the given vertex 'rempt' (p) from the //
20829 // tetrahedralization (T) by a sequence of flips. //
20830 // //
20831 // The algorithm used here is a simple edge reduce method. Suppose there are //
20832 // n edges connected at p. We try to reduce the number of edges by flipping //
20833 // any edge (not a segment) that is connecting at p. //
20834 // //
20835 // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
20836 // can be successfully removed. //
20837 // //
20839 
20840 int tetgenmesh::removevertexbyflips(point steinerpt)
20841 {
20842  triface *fliptets = NULL, wrktets[4];
20843  triface searchtet, spintet, neightet;
20844  face parentsh, spinsh, checksh;
20845  face leftseg, rightseg, checkseg;
20846  point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
20847  flipconstraints fc;
20848  enum verttype vt;
20849  enum locateresult loc;
20850  int valence, removeflag;
20851  int slawson;
20852  int t1ver;
20853  int n, i;
20854 
20855  vt = pointtype(steinerpt);
20856 
20857 
20858  if (vt == FREESEGVERTEX) {
20859  sdecode(point2sh(steinerpt), leftseg);
20860  leftseg.shver = 0;
20861  if (sdest(leftseg) == steinerpt) {
20862  senext(leftseg, rightseg);
20863  spivotself(rightseg);
20864  rightseg.shver = 0;
20865  } else {
20866  rightseg = leftseg;
20867  senext2(rightseg, leftseg);
20868  spivotself(leftseg);
20869  leftseg.shver = 0;
20870  }
20871  lpt = sorg(leftseg);
20872  rpt = sdest(rightseg);
20873  if (b->verbose > 2) {
20874  printf(" Removing Steiner point %d in segment (%d, %d).\n",
20875  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
20876 
20877  }
20878  } else if (vt == FREEFACETVERTEX) {
20879  if (b->verbose > 2) {
20880  printf(" Removing Steiner point %d in facet.\n",
20881  pointmark(steinerpt));
20882  }
20883  } else if (vt == FREEVOLVERTEX) {
20884  if (b->verbose > 2) {
20885  printf(" Removing Steiner point %d in volume.\n",
20886  pointmark(steinerpt));
20887  }
20888  } else if (vt == VOLVERTEX) {
20889  if (b->verbose > 2) {
20890  printf(" Removing a point %d in volume.\n",
20891  pointmark(steinerpt));
20892  }
20893  } else {
20894  // It is not a Steiner point.
20895  return 0;
20896  }
20897 
20898  // Try to reduce the number of edges at 'p' by flips.
20899  getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
20900  cavetetlist->restart(); // This list may be re-used.
20901  if (cavetetvertlist->objects > 3l) {
20902  valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
20903  } else {
20904  valence = cavetetvertlist->objects;
20905  }
20906  cavetetvertlist->restart();
20907 
20908  removeflag = 0;
20909 
20910  if (valence == 4) {
20911  // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
20912  // vertices. This case is due to that 'p' is not exactly on the segment.
20913  point2tetorg(steinerpt, searchtet);
20914  loc = INTETRAHEDRON;
20915  removeflag = 1;
20916  } else if (valence == 5) {
20917  // There are 5 edges.
20918  if (vt == FREESEGVERTEX) {
20919  sstpivot1(leftseg, searchtet);
20920  if (org(searchtet) != steinerpt) {
20921  esymself(searchtet);
20922  }
20923  i = 0; // Count the numbe of tet at the edge [p,lpt].
20924  neightet.tet = NULL; // Init the face.
20925  spintet = searchtet;
20926  while (1) {
20927  i++;
20928  if (apex(spintet) == rpt) {
20929  // Remember the face containing the edge [lpt, rpt].
20930  neightet = spintet;
20931  }
20932  fnextself(spintet);
20933  if (spintet.tet == searchtet.tet) break;
20934  }
20935  if (i == 3) {
20936  // This case has been checked below.
20937  } else if (i == 4) {
20938  // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
20939  // at [p,rpt]. There must be a face [p, lpt, rpt].
20940  if (apex(neightet) == rpt) {
20941  // The edge (segment) has been already recovered!
20942  // Check if a 6-to-2 flip is possible (to remove 'p').
20943  // Let 'searchtet' be [p,d,a,b]
20944  esym(neightet, searchtet);
20945  enextself(searchtet);
20946  // Check if there are exactly three tets at edge [p,d].
20947  wrktets[0] = searchtet; // [p,d,a,b]
20948  for (i = 0; i < 2; i++) {
20949  fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
20950  }
20951  if (apex(wrktets[0]) == oppo(wrktets[2])) {
20952  loc = ONFACE;
20953  removeflag = 1;
20954  }
20955  }
20956  }
20957  } else if (vt == FREEFACETVERTEX) {
20958  // It is possible to do a 6-to-2 flip to remove the vertex.
20959  point2tetorg(steinerpt, searchtet);
20960  // Get the three faces of 'searchtet' which share at p.
20961  // All faces has p as origin.
20962  wrktets[0] = searchtet;
20963  wrktets[1] = searchtet;
20964  esymself(wrktets[1]);
20965  enextself(wrktets[1]);
20966  wrktets[2] = searchtet;
20967  eprevself(wrktets[2]);
20968  esymself(wrktets[2]);
20969  // All internal edges of the six tets have valance either 3 or 4.
20970  // Get one edge which has valance 3.
20971  searchtet.tet = NULL;
20972  for (i = 0; i < 3; i++) {
20973  spintet = wrktets[i];
20974  valence = 0;
20975  while (1) {
20976  valence++;
20977  fnextself(spintet);
20978  if (spintet.tet == wrktets[i].tet) break;
20979  }
20980  if (valence == 3) {
20981  // Found the edge.
20982  searchtet = wrktets[i];
20983  break;
20984  }
20985  }
20986  // Note, we do not detach the three subfaces at p.
20987  // They will be removed within a 4-to-1 flip.
20988  loc = ONFACE;
20989  removeflag = 1;
20990  }
20991  //removeflag = 1;
20992  }
20993 
20994  if (!removeflag) {
20995  if (vt == FREESEGVERTEX) {
20996  // Check is it possible to recover the edge [lpt,rpt].
20997  // The condition to check is: Whether each tet containing 'leftseg' is
20998  // adjacent to a tet containing 'rightseg'.
20999  sstpivot1(leftseg, searchtet);
21000  if (org(searchtet) != steinerpt) {
21001  esymself(searchtet);
21002  }
21003  spintet = searchtet;
21004  while (1) {
21005  // Go to the bottom face of this tet.
21006  eprev(spintet, neightet);
21007  esymself(neightet); // [steinerpt, p1, p2, lpt]
21008  // Get the adjacent tet.
21009  fsymself(neightet); // [p1, steinerpt, p2, rpt]
21010  if (oppo(neightet) != rpt) {
21011  // Found a non-matching adjacent tet.
21012  break;
21013  }
21014  {
21015  // [2017-10-15] Check if the tet is inverted?
21016  point chkp1 = org(neightet);
21017  point chkp2 = apex(neightet);
21018  REAL chkori = orient3d(rpt, lpt, chkp1, chkp2);
21019  if (chkori >= 0.0) {
21020  // Either inverted or degenerated.
21021  break;
21022  }
21023  }
21024  fnextself(spintet);
21025  if (spintet.tet == searchtet.tet) {
21026  // 'searchtet' is [p,d,p1,p2].
21027  loc = ONEDGE;
21028  removeflag = 1;
21029  break;
21030  }
21031  }
21032  } // if (vt == FREESEGVERTEX)
21033  }
21034 
21035  if (!removeflag) {
21036  if (vt == FREESEGVERTEX) {
21037  // Check if the edge [lpt, rpt] exists.
21038  if (getedge(lpt, rpt, &searchtet)) {
21039  // We have recovered this edge. Shift the vertex into the volume.
21040  // We can recover this edge if the subfaces are not recovered yet.
21041  if (!checksubfaceflag) {
21042  // Remove the vertex from the surface mesh.
21043  // This will re-create the segment [lpt, rpt] and re-triangulate
21044  // all the facets at the segment.
21045  // Detach the subsegments from their surrounding tets.
21046  for (i = 0; i < 2; i++) {
21047  checkseg = (i == 0) ? leftseg : rightseg;
21048  sstpivot1(checkseg, neightet);
21049  spintet = neightet;
21050  while (1) {
21051  tssdissolve1(spintet);
21052  fnextself(spintet);
21053  if (spintet.tet == neightet.tet) break;
21054  }
21055  sstdissolve1(checkseg);
21056  } // i
21057  slawson = 1; // Do lawson flip after removal.
21058  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21059  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
21060  // Clear the list for new subfaces.
21061  caveshbdlist->restart();
21062  // Insert the new segment.
21063  sstbond1(rightseg, searchtet);
21064  spintet = searchtet;
21065  while (1) {
21066  tssbond1(spintet, rightseg);
21067  fnextself(spintet);
21068  if (spintet.tet == searchtet.tet) break;
21069  }
21070  // The Steiner point has been shifted into the volume.
21071  setpointtype(steinerpt, FREEVOLVERTEX);
21072  st_segref_count--;
21073  st_volref_count++;
21074  return 1;
21075  } // if (!checksubfaceflag)
21076  } // if (getedge(...))
21077  } // if (vt == FREESEGVERTEX)
21078  } // if (!removeflag)
21079 
21080  if (!removeflag) {
21081  return 0;
21082  }
21083 
21084  if (vt == FREESEGVERTEX) {
21085  // Detach the subsegments from their surronding tets.
21086  for (i = 0; i < 2; i++) {
21087  checkseg = (i == 0) ? leftseg : rightseg;
21088  sstpivot1(checkseg, neightet);
21089  spintet = neightet;
21090  while (1) {
21091  tssdissolve1(spintet);
21092  fnextself(spintet);
21093  if (spintet.tet == neightet.tet) break;
21094  }
21095  sstdissolve1(checkseg);
21096  } // i
21097  if (checksubfaceflag) {
21098  // Detach the subfaces at the subsegments from their attached tets.
21099  for (i = 0; i < 2; i++) {
21100  checkseg = (i == 0) ? leftseg : rightseg;
21101  spivot(checkseg, parentsh);
21102  if (parentsh.sh != NULL) {
21103  spinsh = parentsh;
21104  while (1) {
21105  stpivot(spinsh, neightet);
21106  if (neightet.tet != NULL) {
21107  tsdissolve(neightet);
21108  }
21109  sesymself(spinsh);
21110  stpivot(spinsh, neightet);
21111  if (neightet.tet != NULL) {
21112  tsdissolve(neightet);
21113  }
21114  stdissolve(spinsh);
21115  spivotself(spinsh); // Go to the next subface.
21116  if (spinsh.sh == parentsh.sh) break;
21117  }
21118  }
21119  } // i
21120  } // if (checksubfaceflag)
21121  }
21122 
21123  if (loc == INTETRAHEDRON) {
21124  // Collect the four tets containing 'p'.
21125  fliptets = new triface[4];
21126  fliptets[0] = searchtet; // [p,d,a,b]
21127  for (i = 0; i < 2; i++) {
21128  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
21129  }
21130  eprev(fliptets[0], fliptets[3]);
21131  fnextself(fliptets[3]); // it is [a,p,b,c]
21132  eprevself(fliptets[3]);
21133  esymself(fliptets[3]); // [a,b,c,p].
21134  // Remove p by a 4-to-1 flip.
21135  //flip41(fliptets, 1, 0, 0);
21136  /*
21137  { // Do not flip if there are wrong number of subfaces inside.
21138  // Check if there are three subfaces at 'p'.
21139  triface newface; face flipshs[3];
21140  int spivot = 0, scount = 0;
21141  for (i = 0; i < 3; i++) {
21142  fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
21143  tspivot(newface, flipshs[i]);
21144  if (flipshs[i].sh != NULL) {
21145  spivot = i; // Remember this subface.
21146  scount++;
21147  }
21148  enextself(fliptets[3]);
21149  }
21150  if (scount > 0) {
21151  // There are three subfaces connecting at p.
21152  // Only do flip if a 3-to-1 flip is possible at p at the bottom face.
21153  if (scount != 3) {
21154  // Wrong number of subfaces. Do not flip.
21155  delete [] fliptets;
21156  return 0;
21157  }
21158  // [2018-03-07] an old fix, not 100% safe.
21159  // if (scount < 3) {
21160  // // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
21161  // // assert(scount == 1); // spivot >= 0
21162  // if (scount != 1) {
21163  // // Wrong number of subfaces. Do not flip.
21164  // delete [] fliptets;
21165  // return 0;
21166  // }
21167  //}
21168  }
21169  }
21170  */
21171  if (vt == FREEFACETVERTEX) {
21172  // [2018-03-08] Check if the last 4-to-1 flip is valid.
21173  // fliptets[0],[1],[2] are [p,d,a,b],[p,d,b,c],[p,d,c,a]
21174  triface checktet, chkface;
21175  for (i = 0; i < 3; i++) {
21176  enext(fliptets[i], checktet);
21177  esymself(checktet); // [a,d,b,p],[b,d,c,p],[c,d,a,p]
21178  int scount = 0; int k;
21179  for (k = 0; k < 3; k++) {
21180  esym(checktet, chkface);
21181  if (issubface(chkface)) scount++;
21182  enextself(checktet);
21183  }
21184  if (scount == 3) {
21185  break; // Found a tet which support a 3-to-1 flip.
21186  } else if (scount == 2) {
21187  // This is a strange configuration. Debug it.
21188  // Do not do this flip.
21189  delete [] fliptets;
21190  return 0;
21191  }
21192  }
21193  if (i == 3) {
21194  // No tet in [p,d,a,b],[p,d,b,c],[p,d,c,a] support it.
21195  int scount = 0;
21196  for (i = 0; i < 3; i++) {
21197  eprev(fliptets[i], checktet);
21198  esymself(checktet); // [p,a,b,d],[p,b,c,d],[p,c,a,d]
21199  if (issubface(chkface)) scount++;
21200  }
21201  if (scount != 3) {
21202  // Do not do this flip.
21203  delete [] fliptets;
21204  return 0;
21205  }
21206  }
21207  } // if (vt == FREEFACETVERTEX)
21208  flip41(fliptets, 1, &fc);
21209  //recenttet = fliptets[0];
21210  } else if (loc == ONFACE) {
21211  // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
21212  // face [a,b,c]. Let 'searchtet' be the tet [p,d,a,b].
21213  // Collect the six tets containing 'p'.
21214  fliptets = new triface[6];
21215  fliptets[0] = searchtet; // [p,d,a,b]
21216  for (i = 0; i < 2; i++) {
21217  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
21218  }
21219  eprev(fliptets[0], fliptets[3]);
21220  fnextself(fliptets[3]); // [a,p,b,e]
21221  esymself(fliptets[3]); // [p,a,e,b]
21222  eprevself(fliptets[3]); // [e,p,a,b]
21223  for (i = 3; i < 5; i++) {
21224  fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
21225  }
21226  if (vt == FREEFACETVERTEX) {
21227  // We need to determine the location of three subfaces at p.
21228  valence = 0; // Re-use it.
21229  for (i = 3; i < 6; i++) {
21230  if (issubface(fliptets[i])) valence++;
21231  }
21232  if (valence > 0) {
21233  // We must do 3-to-2 flip in the upper part. We simply re-arrange
21234  // the six tets.
21235  for (i = 0; i < 3; i++) {
21236  esym(fliptets[i+3], wrktets[i]);
21237  esym(fliptets[i], fliptets[i+3]);
21238  fliptets[i] = wrktets[i];
21239  }
21240  // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
21241  wrktets[1] = fliptets[1];
21242  fliptets[1] = fliptets[2];
21243  fliptets[2] = wrktets[1];
21244  wrktets[1] = fliptets[4];
21245  fliptets[4] = fliptets[5];
21246  fliptets[5] = wrktets[1];
21247  }
21248  // [2018-03-08] Check if the last 4-to-1 flip is valid.
21249  // fliptets[0],[1],[2] are [p,d,a,b],[p,d,b,c],[p,d,c,a]
21250  triface checktet, chkface;
21251  for (i = 0; i < 3; i++) {
21252  enext(fliptets[i], checktet);
21253  esymself(checktet); // [a,d,b,p],[b,d,c,p],[c,d,a,p]
21254  int scount = 0; int k;
21255  for (k = 0; k < 3; k++) {
21256  esym(checktet, chkface);
21257  if (issubface(chkface)) scount++;
21258  enextself(checktet);
21259  }
21260  if (scount == 3) {
21261  break; // Found a tet which support a 3-to-1 flip.
21262  } else if (scount == 2) {
21263  // This is a strange configuration. Debug it.
21264  // Do not do this flip.
21265  delete [] fliptets;
21266  return 0;
21267  }
21268  }
21269  if (i == 3) {
21270  // No tet in [p,d,a,b],[p,d,b,c],[p,d,c,a] support it.
21271  int scount = 0;
21272  for (i = 0; i < 3; i++) {
21273  eprev(fliptets[i], checktet);
21274  esymself(checktet); // [p,a,b,d],[p,b,c,d],[p,c,a,d]
21275  if (issubface(chkface)) scount++;
21276  }
21277  if (scount != 3) {
21278  // Do not do this flip.
21279  delete [] fliptets;
21280  return 0;
21281  }
21282  }
21283  } // vt == FREEFACETVERTEX
21284  // Remove p by a 6-to-2 flip, which is a combination of two flips:
21285  // a 3-to-2 (deletes the edge [e,p]), and
21286  // a 4-to-1 (deletes the vertex p).
21287  // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
21288  // two new tets: [a,b,c,p] and [b,a,c,e]. The new tet [a,b,c,p] is
21289  // degenerate (has zero volume). It will be deleted in the followed
21290  // 4-to-1 flip.
21291  //flip32(&(fliptets[3]), 1, 0, 0);
21292  flip32(&(fliptets[3]), 1, &fc);
21293  // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
21294  // This creates a new tet [a,b,c,d].
21295  //flip41(fliptets, 1, 0, 0);
21296  flip41(fliptets, 1, &fc);
21297  //recenttet = fliptets[0];
21298  } else if (loc == ONEDGE) {
21299  // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
21300  // tets sharing at edge [e,d] originally. We number the link vertices
21301  // of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
21302  // Count the number of tets at edge [e,p] and [p,d] (this is n).
21303  n = 0;
21304  spintet = searchtet;
21305  while (1) {
21306  n++;
21307  fnextself(spintet);
21308  if (spintet.tet == searchtet.tet) break;
21309  }
21310  // Collect the 2n tets containing 'p'.
21311  fliptets = new triface[2 * n];
21312  fliptets[0] = searchtet; // [p,b,p_0,p_1]
21313  for (i = 0; i < (n - 1); i++) {
21314  fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
21315  }
21316  eprev(fliptets[0], fliptets[n]);
21317  fnextself(fliptets[n]); // [p_0,p,p_1,e]
21318  esymself(fliptets[n]); // [p,p_0,e,p_1]
21319  eprevself(fliptets[n]); // [e,p,p_0,p_1]
21320  for (i = n; i < (2 * n - 1); i++) {
21321  fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
21322  }
21323  // Remove p by a 2n-to-n flip, it is a sequence of n flips:
21324  // - Do a 2-to-3 flip on
21325  // [p_0,p_1,p,d] and
21326  // [p,p_1,p_0,e].
21327  // This produces:
21328  // [e,d,p_0,p_1],
21329  // [e,d,p_1,p] (degenerated), and
21330  // [e,d,p,p_0] (degenerated).
21331  wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
21332  eprevself(wrktets[0]); // [p_0,p,d,p_1]
21333  esymself(wrktets[0]); // [p,p_0,p_1,d]
21334  enextself(wrktets[0]); // [p_0,p_1,p,d] [0]
21335  wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
21336  enextself(wrktets[1]); // [p,p_0,e,p_1]
21337  esymself(wrktets[1]); // [p_0,p,p_1,e]
21338  eprevself(wrktets[1]); // [p_1,p_0,p,e] [1]
21339  //flip23(wrktets, 1, 0, 0);
21340  flip23(wrktets, 1, &fc);
21341  // Save the new tet [e,d,p,p_0] (degenerated).
21342  fliptets[n] = wrktets[2];
21343  // Save the new tet [e,d,p_0,p_1].
21344  fliptets[0] = wrktets[0];
21345  // - Repeat from i = 1 to n-2: (n - 2) flips
21346  // - Do a 3-to-2 flip on
21347  // [p,p_i,d,e],
21348  // [p,p_i,e,p_i+1], and
21349  // [p,p_i,p_i+1,d].
21350  // This produces:
21351  // [d,e,p_i+1,p_i], and
21352  // [e,d,p_i+1,p] (degenerated).
21353  for (i = 1; i < (n - 1); i++) {
21354  wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
21355  enextself(wrktets[0]); // [d,p_i,e,p] (...)
21356  esymself(wrktets[0]); // [p_i,d,p,e] (...)
21357  eprevself(wrktets[0]); // [p,p_i,d,e] (degenerated) [0].
21358  wrktets[1] = fliptets[n+i]; // [e,p,p_i,p_i+1]
21359  enextself(wrktets[1]); // [p,p_i,e,p_i+1] [1]
21360  wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
21361  eprevself(wrktets[2]); // [p_i,p,d,p_i+1]
21362  esymself(wrktets[2]); // [p,p_i,p_i+1,d] [2]
21363  //flip32(wrktets, 1, 0, 0);
21364  flip32(wrktets, 1, &fc);
21365  // Save the new tet [e,d,p_i,p_i+1]. // FOR DEBUG ONLY
21366  fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
21367  esymself(fliptets[i]); // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
21368  }
21369  // - Do a 4-to-1 flip on
21370  // [p,p_0,e,d], [d,e,p_0,p],
21371  // [p,p_0,d,p_n-1], [e,p_n-1,p_0,p],
21372  // [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
21373  // [e,d,p_n-1,p].
21374  // This produces
21375  // [e,d,p_n-1,p_0] and
21376  // deletes p.
21377  wrktets[3] = wrktets[1]; // [e,d,p_n-1,p] (degenerated) [3]
21378  wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
21379  eprevself(wrktets[0]); // [p,e,d,p_0] (...)
21380  esymself(wrktets[0]); // [e,p,p_0,d] (...)
21381  enextself(wrktets[0]); // [p,p_0,e,d] (degenerated) [0]
21382  wrktets[1] = fliptets[n-1]; // [p,d,p_n-1,p_0]
21383  esymself(wrktets[1]); // [d,p,p_0,p_n-1]
21384  enextself(wrktets[1]); // [p,p_0,d,p_n-1] [1]
21385  wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
21386  enextself(wrktets[2]); // [p_p_n-1,e,p_0]
21387  esymself(wrktets[2]); // [p_n-1,p,p_0,e]
21388  enextself(wrktets[2]); // [p,p_0,p_n-1,e] [2]
21389  //flip41(wrktets, 1, 0, 0);
21390  flip41(wrktets, 1, &fc);
21391  // Save the new tet [e,d,p_n-1,p_0] // FOR DEBUG ONLY
21392  fliptets[n-1] = wrktets[0]; // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
21393  //recenttet = fliptets[0];
21394  }
21395 
21396  delete [] fliptets;
21397 
21398  if (vt == FREESEGVERTEX) {
21399  // Remove the vertex from the surface mesh.
21400  // This will re-create the segment [lpt, rpt] and re-triangulate
21401  // all the facets at the segment.
21402  // Only do lawson flip when subfaces are not recovery yet.
21403  slawson = (checksubfaceflag ? 0 : 1);
21404  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21405  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
21406 
21407  // The original segment is returned in 'rightseg'.
21408  rightseg.shver = 0;
21409  // Insert the new segment.
21410  point2tetorg(lpt, searchtet);
21411  finddirection(&searchtet, rpt);
21412  sstbond1(rightseg, searchtet);
21413  spintet = searchtet;
21414  while (1) {
21415  tssbond1(spintet, rightseg);
21416  fnextself(spintet);
21417  if (spintet.tet == searchtet.tet) break;
21418  }
21419 
21420  if (checksubfaceflag) {
21421  // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
21422  spivot(rightseg, parentsh);
21423  if (parentsh.sh != NULL) {
21424  spinsh = parentsh;
21425  while (1) {
21426  if (sorg(spinsh) != lpt) {
21427  sesymself(spinsh);
21428  }
21429  apexpt = sapex(spinsh);
21430  // Find the adjacent tet of [lpt,rpt,apexpt];
21431  spintet = searchtet;
21432  while (1) {
21433  if (apex(spintet) == apexpt) {
21434  tsbond(spintet, spinsh);
21435  sesymself(spinsh); // Get to another side of this face.
21436  fsym(spintet, neightet);
21437  tsbond(neightet, spinsh);
21438  sesymself(spinsh); // Get back to the original side.
21439  break;
21440  }
21441  fnextself(spintet);
21442  }
21443  spivotself(spinsh);
21444  if (spinsh.sh == parentsh.sh) break;
21445  }
21446  }
21447  } // if (checksubfaceflag)
21448 
21449  // Clear the set of new subfaces.
21450  caveshbdlist->restart();
21451  } // if (vt == FREESEGVERTEX)
21452 
21453  // The point has been removed.
21454  if (pointtype(steinerpt) != UNUSEDVERTEX) {
21455  setpointtype(steinerpt, UNUSEDVERTEX);
21456  unuverts++;
21457  }
21458  if (vt != VOLVERTEX) {
21459  // Update the correspinding counters.
21460  if (vt == FREESEGVERTEX) {
21461  st_segref_count--;
21462  } else if (vt == FREEFACETVERTEX) {
21463  st_facref_count--;
21464  } else if (vt == FREEVOLVERTEX) {
21465  st_volref_count--;
21466  }
21467  if (steinerleft > 0) steinerleft++;
21468  }
21469 
21470  return 1;
21471 }
21472 
21474 // //
21475 // suppressbdrysteinerpoint() Suppress a boundary Steiner point //
21476 // //
21478 
21479 int tetgenmesh::suppressbdrysteinerpoint(point steinerpt)
21480 {
21481  face parentsh, spinsh, *parysh;
21482  face leftseg, rightseg;
21483  point lpt = NULL, rpt = NULL;
21484  int i;
21485 
21486  verttype vt = pointtype(steinerpt);
21487 
21488  if (vt == FREESEGVERTEX) {
21489  sdecode(point2sh(steinerpt), leftseg);
21490  leftseg.shver = 0;
21491  if (sdest(leftseg) == steinerpt) {
21492  senext(leftseg, rightseg);
21493  spivotself(rightseg);
21494  rightseg.shver = 0;
21495  } else {
21496  rightseg = leftseg;
21497  senext2(rightseg, leftseg);
21498  spivotself(leftseg);
21499  leftseg.shver = 0;
21500  }
21501  lpt = sorg(leftseg);
21502  rpt = sdest(rightseg);
21503  if (b->verbose > 2) {
21504  printf(" Suppressing Steiner point %d in segment (%d, %d).\n",
21505  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
21506  }
21507  // Get all subfaces at the left segment [lpt, steinerpt].
21508  spivot(leftseg, parentsh);
21509  if (parentsh.sh != NULL) {
21510  // It is not a dangling segment.
21511  spinsh = parentsh;
21512  while (1) {
21513  cavesegshlist->newindex((void **) &parysh);
21514  *parysh = spinsh;
21515  // Orient the face consistently.
21516  if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
21517  spivotself(spinsh);
21518  if (spinsh.sh == NULL) break;
21519  if (spinsh.sh == parentsh.sh) break;
21520  }
21521  }
21522  if (cavesegshlist->objects < 2) {
21523  // It is a single segment. Not handle it yet.
21524  cavesegshlist->restart();
21525  return 0;
21526  }
21527  } else if (vt == FREEFACETVERTEX) {
21528  if (b->verbose > 2) {
21529  printf(" Suppressing Steiner point %d from facet.\n",
21530  pointmark(steinerpt));
21531  }
21532  sdecode(point2sh(steinerpt), parentsh);
21533  // A facet Steiner point. There are exactly two sectors.
21534  for (i = 0; i < 2; i++) {
21535  cavesegshlist->newindex((void **) &parysh);
21536  *parysh = parentsh;
21537  sesymself(parentsh);
21538  }
21539  } else {
21540  return 0;
21541  }
21542 
21543  triface searchtet, neightet, *parytet;
21544  point pa, pb, pc, pd;
21545  REAL v1[3], v2[3], len, u;
21546 
21547  REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
21548  REAL ori, minvol, smallvol;
21549  int samplesize;
21550  int it, j, k;
21551 
21552  int n = (int) cavesegshlist->objects;
21553  point *newsteiners = new point[n];
21554  for (i = 0; i < n; i++) newsteiners[i] = NULL;
21555 
21556  // Search for each sector an interior vertex.
21557  for (i = 0; i < cavesegshlist->objects; i++) {
21558  parysh = (face *) fastlookup(cavesegshlist, i);
21559  stpivot(*parysh, searchtet);
21560  // Skip it if it is outside.
21561  if (ishulltet(searchtet)) continue;
21562  // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
21563  // opposite. Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
21564  // Moreover, subfaces are oriented towards the interior of the ball.
21565  setpoint2tet(steinerpt, encode(searchtet));
21566  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
21567  // Calculate the searching vector.
21568  pa = sorg(*parysh);
21569  pb = sdest(*parysh);
21570  pc = sapex(*parysh);
21571  facenormal(pa, pb, pc, v1, 1, NULL);
21572  len = sqrt(dot(v1, v1));
21573  v1[0] /= len;
21574  v1[1] /= len;
21575  v1[2] /= len;
21576  if (vt == FREESEGVERTEX) {
21577  parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
21578  pd = sapex(*parysh);
21579  facenormal(pb, pa, pd, v2, 1, NULL);
21580  len = sqrt(dot(v2, v2));
21581  v2[0] /= len;
21582  v2[1] /= len;
21583  v2[2] /= len;
21584  // Average the two vectors.
21585  v1[0] = 0.5 * (v1[0] + v2[0]);
21586  v1[1] = 0.5 * (v1[1] + v2[1]);
21587  v1[2] = 0.5 * (v1[2] + v2[2]);
21588  }
21589  // Search the intersection of the ray starting from 'steinerpt' to
21590  // the search direction 'v1' and the shell of the half-ball.
21591  // - Construct an endpoint.
21592  len = distance(pa, pb);
21593  v2[0] = steinerpt[0] + len * v1[0];
21594  v2[1] = steinerpt[1] + len * v1[1];
21595  v2[2] = steinerpt[2] + len * v1[2];
21596  for (j = 0; j < cavetetlist->objects; j++) {
21597  parytet = (triface *) fastlookup(cavetetlist, j);
21598  pa = org(*parytet);
21599  pb = dest(*parytet);
21600  pc = apex(*parytet);
21601  // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
21602  // is the apex, and three sides are defined by the triangle
21603  // [pa, pb, pc].
21604  ori = orient3d(steinerpt, pa, pb, v2);
21605  if (ori >= 0) {
21606  ori = orient3d(steinerpt, pb, pc, v2);
21607  if (ori >= 0) {
21608  ori = orient3d(steinerpt, pc, pa, v2);
21609  if (ori >= 0) {
21610  // Found! Calculate the intersection.
21611  planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
21612  break;
21613  }
21614  }
21615  }
21616  } // j
21617  if (j == cavetetlist->objects) {
21618  break; // There is no intersection!! Debug is needed.
21619  }
21620  // Close the ball by adding the subfaces.
21621  for (j = 0; j < caveshlist->objects; j++) {
21622  parysh = (face *) fastlookup(caveshlist, j);
21623  stpivot(*parysh, neightet);
21624  cavetetlist->newindex((void **) &parytet);
21625  *parytet = neightet;
21626  }
21627  // Search a best point inside the segment [startpt, steinerpt].
21628  it = 0;
21629  samplesize = 100;
21630  v1[0] = steinerpt[0] - startpt[0];
21631  v1[1] = steinerpt[1] - startpt[1];
21632  v1[2] = steinerpt[2] - startpt[2];
21633  minvol = -1.0;
21634  while (it < 3) {
21635  for (j = 1; j < samplesize - 1; j++) {
21636  samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
21637  samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
21638  samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
21639  // Find the minimum volume for 'samplept'.
21640  smallvol = -1;
21641  for (k = 0; k < cavetetlist->objects; k++) {
21642  parytet = (triface *) fastlookup(cavetetlist, k);
21643  pa = org(*parytet);
21644  pb = dest(*parytet);
21645  pc = apex(*parytet);
21646  ori = orient3d(pb, pa, pc, samplept);
21647  {
21648  // [2017-10-15] Rounding
21649  REAL lab = distance(pa, pb);
21650  REAL lbc = distance(pb, pc);
21651  REAL lca = distance(pc, pa);
21652  REAL lv = (lab + lbc + lca) / 3.0;
21653  REAL l3 = lv*lv*lv;
21654  if (fabs(ori) / l3 < 1e-8) ori = 0.0;
21655  }
21656  if (ori <= 0) {
21657  break; // An invalid tet.
21658  }
21659  if (smallvol == -1) {
21660  smallvol = ori;
21661  } else {
21662  if (ori < smallvol) smallvol = ori;
21663  }
21664  } // k
21665  if (k == cavetetlist->objects) {
21666  // Found a valid point. Remember it.
21667  if (minvol == -1.0) {
21668  candpt[0] = samplept[0];
21669  candpt[1] = samplept[1];
21670  candpt[2] = samplept[2];
21671  minvol = smallvol;
21672  } else {
21673  if (minvol < smallvol) {
21674  // It is a better location. Remember it.
21675  candpt[0] = samplept[0];
21676  candpt[1] = samplept[1];
21677  candpt[2] = samplept[2];
21678  minvol = smallvol;
21679  } else {
21680  // No improvement of smallest volume.
21681  // Since we are searching along the line [startpt, steinerpy],
21682  // The smallest volume can only be decreased later.
21683  break;
21684  }
21685  }
21686  }
21687  } // j
21688  if (minvol > 0) break;
21689  samplesize *= 10;
21690  it++;
21691  } // while (it < 3)
21692  if (minvol == -1.0) {
21693  // Failed to find a valid point.
21694  cavetetlist->restart();
21695  caveshlist->restart();
21696  break;
21697  }
21698  // Create a new Steiner point inside this section.
21699  makepoint(&(newsteiners[i]), FREEVOLVERTEX);
21700  newsteiners[i][0] = candpt[0];
21701  newsteiners[i][1] = candpt[1];
21702  newsteiners[i][2] = candpt[2];
21703  cavetetlist->restart();
21704  caveshlist->restart();
21705  } // i
21706 
21707  if (i < cavesegshlist->objects) {
21708  // Failed to suppress the vertex.
21709  for (; i > 0; i--) {
21710  if (newsteiners[i - 1] != NULL) {
21711  pointdealloc(newsteiners[i - 1]);
21712  }
21713  }
21714  delete [] newsteiners;
21715  cavesegshlist->restart();
21716  return 0;
21717  }
21718 
21719  // Remove p from the segment or the facet.
21720  triface newtet, newface, spintet;
21721  face newsh, neighsh;
21722  face *splitseg, checkseg;
21723  int slawson = 0; // Do not do flip afterword.
21724  int t1ver;
21725 
21726  if (vt == FREESEGVERTEX) {
21727  // Detach 'leftseg' and 'rightseg' from their adjacent tets.
21728  // These two subsegments will be deleted.
21729  sstpivot1(leftseg, neightet);
21730  spintet = neightet;
21731  while (1) {
21732  tssdissolve1(spintet);
21733  fnextself(spintet);
21734  if (spintet.tet == neightet.tet) break;
21735  }
21736  sstpivot1(rightseg, neightet);
21737  spintet = neightet;
21738  while (1) {
21739  tssdissolve1(spintet);
21740  fnextself(spintet);
21741  if (spintet.tet == neightet.tet) break;
21742  }
21743  }
21744 
21745  // Loop through all sectors bounded by facets at this segment.
21746  // Within each sector, create a new Steiner point 'np', and replace 'p'
21747  // by 'np' for all tets in this sector.
21748  for (i = 0; i < cavesegshlist->objects; i++) {
21749  parysh = (face *) fastlookup(cavesegshlist, i);
21750  // 'parysh' is the face [lpt, steinerpt, #].
21751  stpivot(*parysh, neightet);
21752  // Get all tets in this sector.
21753  setpoint2tet(steinerpt, encode(neightet));
21754  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
21755  if (!ishulltet(neightet)) {
21756  // Within each tet in the ball, replace 'p' by 'np'.
21757  for (j = 0; j < cavetetlist->objects; j++) {
21758  parytet = (triface *) fastlookup(cavetetlist, j);
21759  setoppo(*parytet, newsteiners[i]);
21760  } // j
21761  // Point to a parent tet.
21762  parytet = (triface *) fastlookup(cavetetlist, 0);
21763  setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet));
21764  st_volref_count++;
21765  if (steinerleft > 0) steinerleft--;
21766  }
21767  // Disconnect the set of boundary faces. They're temporarily open faces.
21768  // They will be connected to the new tets after 'p' is removed.
21769  for (j = 0; j < caveshlist->objects; j++) {
21770  // Get a boundary face.
21771  parysh = (face *) fastlookup(caveshlist, j);
21772  stpivot(*parysh, neightet);
21773  //assert(apex(neightet) == newpt);
21774  // Clear the connection at this face.
21775  dissolve(neightet);
21776  tsdissolve(neightet);
21777  }
21778  // Clear the working lists.
21779  cavetetlist->restart();
21780  caveshlist->restart();
21781  } // i
21782  cavesegshlist->restart();
21783 
21784  if (vt == FREESEGVERTEX) {
21785  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21786  splitseg = &rightseg;
21787  } else {
21788  if (sdest(parentsh) == steinerpt) {
21789  senextself(parentsh);
21790  } else if (sapex(parentsh) == steinerpt) {
21791  senext2self(parentsh);
21792  }
21793  splitseg = NULL;
21794  }
21795  sremovevertex(steinerpt, &parentsh, splitseg, slawson);
21796 
21797  if (vt == FREESEGVERTEX) {
21798  // The original segment is returned in 'rightseg'.
21799  rightseg.shver = 0;
21800  }
21801 
21802  // For each new subface, create two new tets at each side of it.
21803  // Both of the two new tets have its opposite be dummypoint.
21804  for (i = 0; i < caveshbdlist->objects; i++) {
21805  parysh = (face *) fastlookup(caveshbdlist, i);
21806  sinfect(*parysh); // Mark it for connecting new tets.
21807  newsh = *parysh;
21808  pa = sorg(newsh);
21809  pb = sdest(newsh);
21810  pc = sapex(newsh);
21811  maketetrahedron(&newtet);
21812  maketetrahedron(&neightet);
21813  setvertices(newtet, pa, pb, pc, dummypoint);
21814  setvertices(neightet, pb, pa, pc, dummypoint);
21815  bond(newtet, neightet);
21816  tsbond(newtet, newsh);
21817  sesymself(newsh);
21818  tsbond(neightet, newsh);
21819  }
21820  // Temporarily increase the hullsize.
21821  hullsize += (caveshbdlist->objects * 2l);
21822 
21823  if (vt == FREESEGVERTEX) {
21824  // Connecting new tets at the recovered segment.
21825  spivot(rightseg, parentsh);
21826  spinsh = parentsh;
21827  while (1) {
21828  if (sorg(spinsh) != lpt) sesymself(spinsh);
21829  // Get the new tet at this subface.
21830  stpivot(spinsh, newtet);
21831  tssbond1(newtet, rightseg);
21832  // Go to the other face at this segment.
21833  spivot(spinsh, neighsh);
21834  if (sorg(neighsh) != lpt) sesymself(neighsh);
21835  sesymself(neighsh);
21836  stpivot(neighsh, neightet);
21837  tssbond1(neightet, rightseg);
21838  sstbond1(rightseg, neightet);
21839  // Connecting two adjacent tets at this segment.
21840  esymself(newtet);
21841  esymself(neightet);
21842  // Connect the two tets (at rightseg) together.
21843  bond(newtet, neightet);
21844  // Go to the next subface.
21845  spivotself(spinsh);
21846  if (spinsh.sh == parentsh.sh) break;
21847  }
21848  }
21849 
21850  // Connecting new tets at new subfaces together.
21851  for (i = 0; i < caveshbdlist->objects; i++) {
21852  parysh = (face *) fastlookup(caveshbdlist, i);
21853  newsh = *parysh;
21854  //assert(sinfected(newsh));
21855  // Each new subface contains two new tets.
21856  for (k = 0; k < 2; k++) {
21857  stpivot(newsh, newtet);
21858  for (j = 0; j < 3; j++) {
21859  // Check if this side is open.
21860  esym(newtet, newface);
21861  if (newface.tet[newface.ver & 3] == NULL) {
21862  // An open face. Connect it to its adjacent tet.
21863  sspivot(newsh, checkseg);
21864  if (checkseg.sh != NULL) {
21865  // A segment. It must not be the recovered segment.
21866  tssbond1(newtet, checkseg);
21867  sstbond1(checkseg, newtet);
21868  }
21869  spivot(newsh, neighsh);
21870  if (neighsh.sh != NULL) {
21871  // The adjacent subface exists. It's not a dangling segment.
21872  if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
21873  stpivot(neighsh, neightet);
21874  if (sinfected(neighsh)) {
21875  esymself(neightet);
21876  } else {
21877  // Search for an open face at this edge.
21878  spintet = neightet;
21879  while (1) {
21880  esym(spintet, searchtet);
21881  fsym(searchtet, spintet);
21882  if (spintet.tet == NULL) break;
21883  }
21884  // Found an open face at 'searchtet'.
21885  neightet = searchtet;
21886  }
21887  } else {
21888  // The edge (at 'newsh') is a dangling segment.
21889  // Get an adjacent tet at this segment.
21890  sstpivot1(checkseg, neightet);
21891  if (org(neightet) != sdest(newsh)) esymself(neightet);
21892  // Search for an open face at this edge.
21893  spintet = neightet;
21894  while (1) {
21895  esym(spintet, searchtet);
21896  fsym(searchtet, spintet);
21897  if (spintet.tet == NULL) break;
21898  }
21899  // Found an open face at 'searchtet'.
21900  neightet = searchtet;
21901  }
21902  pc = apex(newface);
21903  if (apex(neightet) == steinerpt) {
21904  // Exterior case. The 'neightet' is a hull tet which contain
21905  // 'steinerpt'. It will be deleted after 'steinerpt' is removed.
21906  caveoldtetlist->newindex((void **) &parytet);
21907  *parytet = neightet;
21908  // Connect newface to the adjacent hull tet of 'neightet', which
21909  // has the same edge as 'newface', and does not has 'steinerpt'.
21910  fnextself(neightet);
21911  } else {
21912  if (pc == dummypoint) {
21913  if (apex(neightet) != dummypoint) {
21914  setapex(newface, apex(neightet));
21915  // A hull tet has turned into an interior tet.
21916  hullsize--; // Must update the hullsize.
21917  }
21918  }
21919  }
21920  bond(newface, neightet);
21921  } // if (newface.tet[newface.ver & 3] == NULL)
21922  enextself(newtet);
21923  senextself(newsh);
21924  } // j
21925  sesymself(newsh);
21926  } // k
21927  } // i
21928 
21929  // Unmark all new subfaces.
21930  for (i = 0; i < caveshbdlist->objects; i++) {
21931  parysh = (face *) fastlookup(caveshbdlist, i);
21932  suninfect(*parysh);
21933  }
21934  caveshbdlist->restart();
21935 
21936  if (caveoldtetlist->objects > 0l) {
21937  // Delete hull tets which contain 'steinerpt'.
21938  for (i = 0; i < caveoldtetlist->objects; i++) {
21939  parytet = (triface *) fastlookup(caveoldtetlist, i);
21940  tetrahedrondealloc(parytet->tet);
21941  }
21942  // Must update the hullsize.
21943  hullsize -= caveoldtetlist->objects;
21944  caveoldtetlist->restart();
21945  }
21946 
21947  setpointtype(steinerpt, UNUSEDVERTEX);
21948  unuverts++;
21949  if (vt == FREESEGVERTEX) {
21950  st_segref_count--;
21951  } else { // vt == FREEFACETVERTEX
21952  st_facref_count--;
21953  }
21954  if (steinerleft > 0) steinerleft++; // We've removed a Steiner points.
21955 
21956 
21957  point *parypt;
21958  int steinercount = 0;
21959 
21960  int bak_fliplinklevel = b->fliplinklevel;
21961  b->fliplinklevel = 100000; // Unlimited flip level.
21962 
21963  // Try to remove newly added Steiner points.
21964  for (i = 0; i < n; i++) {
21965  if (newsteiners[i] != NULL) {
21966  if (!removevertexbyflips(newsteiners[i])) {
21967  if (b->supsteiner_level > 0) { // Not -Y/0
21968  // Save it in subvertstack for removal.
21969  subvertstack->newindex((void **) &parypt);
21970  *parypt = newsteiners[i];
21971  }
21972  steinercount++;
21973  }
21974  }
21975  }
21976 
21977  b->fliplinklevel = bak_fliplinklevel;
21978 
21979  if (steinercount > 0) {
21980  if (b->verbose > 2) {
21981  printf(" Added %d interior Steiner points.\n", steinercount);
21982  }
21983  }
21984 
21985  delete [] newsteiners;
21986 
21987  return 1;
21988 }
21989 
21990 
21992 // //
21993 // suppresssteinerpoints() Suppress Steiner points. //
21994 // //
21995 // All Steiner points have been saved in 'subvertstack' in the routines //
21996 // carveholes() and suppresssteinerpoint(). //
21997 // Each Steiner point is either removed or shifted into the interior. //
21998 // //
22000 
22001 int tetgenmesh::suppresssteinerpoints()
22002 {
22003 
22004  if (!b->quiet) {
22005  printf("Suppressing Steiner points ...\n");
22006  }
22007 
22008  point rempt, *parypt;
22009 
22010  int bak_fliplinklevel = b->fliplinklevel;
22011  b->fliplinklevel = 100000; // Unlimited flip level.
22012  int suppcount = 0, remcount = 0;
22013  int i;
22014 
22015  // Try to suppress boundary Steiner points.
22016  for (i = 0; i < subvertstack->objects; i++) {
22017  parypt = (point *) fastlookup(subvertstack, i);
22018  rempt = *parypt;
22019  if (pointtype(rempt) != UNUSEDVERTEX) {
22020  if ((pointtype(rempt) == FREESEGVERTEX) ||
22021  (pointtype(rempt) == FREEFACETVERTEX)) {
22022  if (suppressbdrysteinerpoint(rempt)) {
22023  suppcount++;
22024  }
22025  }
22026  }
22027  } // i
22028 
22029  if (suppcount > 0) {
22030  if (b->verbose) {
22031  printf(" Suppressed %d boundary Steiner points.\n", suppcount);
22032  }
22033  }
22034 
22035  if (b->supsteiner_level > 0) { // -Y/1
22036  for (i = 0; i < subvertstack->objects; i++) {
22037  parypt = (point *) fastlookup(subvertstack, i);
22038  rempt = *parypt;
22039  if (pointtype(rempt) != UNUSEDVERTEX) {
22040  if (pointtype(rempt) == FREEVOLVERTEX) {
22041  if (removevertexbyflips(rempt)) {
22042  remcount++;
22043  }
22044  }
22045  }
22046  }
22047  }
22048 
22049  if (remcount > 0) {
22050  if (b->verbose) {
22051  printf(" Removed %d interior Steiner points.\n", remcount);
22052  }
22053  }
22054 
22055  b->fliplinklevel = bak_fliplinklevel;
22056 
22057  if (b->supsteiner_level > 1) { // -Y/2
22058  // Smooth interior Steiner points.
22059  optparameters opm;
22060  triface *parytet;
22061  point *ppt;
22062  REAL ori;
22063  int smtcount, count, ivcount;
22064  int nt, j;
22065 
22066  // Point smooth options.
22067  opm.max_min_volume = 1;
22068  opm.numofsearchdirs = 20;
22069  opm.searchstep = 0.001;
22070  opm.maxiter = 30; // Limit the maximum iterations.
22071 
22072  smtcount = 0;
22073 
22074  do {
22075 
22076  nt = 0;
22077 
22078  while (1) {
22079  count = 0;
22080  ivcount = 0; // Clear the inverted count.
22081 
22082  for (i = 0; i < subvertstack->objects; i++) {
22083  parypt = (point *) fastlookup(subvertstack, i);
22084  rempt = *parypt;
22085  if (pointtype(rempt) == FREEVOLVERTEX) {
22086  getvertexstar(1, rempt, cavetetlist, NULL, NULL);
22087  // Calculate the initial smallest volume (maybe zero or negative).
22088  for (j = 0; j < cavetetlist->objects; j++) {
22089  parytet = (triface *) fastlookup(cavetetlist, j);
22090  ppt = (point *) &(parytet->tet[4]);
22091  ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
22092  if (j == 0) {
22093  opm.initval = ori;
22094  } else {
22095  if (opm.initval > ori) opm.initval = ori;
22096  }
22097  }
22098  if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
22099  count++;
22100  }
22101  if (opm.imprval <= 0.0) {
22102  ivcount++; // The mesh contains inverted elements.
22103  }
22104  cavetetlist->restart();
22105  }
22106  } // i
22107 
22108  smtcount += count;
22109 
22110  if (count == 0) {
22111  // No point has been smoothed.
22112  break;
22113  }
22114 
22115  nt++;
22116  if (nt > 2) {
22117  break; // Already three iterations.
22118  }
22119  } // while
22120 
22121  if (ivcount > 0) {
22122  // There are inverted elements!
22123  if (opm.maxiter > 0) {
22124  // Set unlimited smoothing steps. Try again.
22125  opm.numofsearchdirs = 30;
22126  opm.searchstep = 0.0001;
22127  opm.maxiter = -1;
22128  continue;
22129  }
22130  }
22131 
22132  break;
22133  } while (1); // Additional loop for (ivcount > 0)
22134 
22135  if (ivcount > 0) {
22136  printf("BUG Report! The mesh contain inverted elements.\n");
22137  }
22138 
22139  if (b->verbose) {
22140  if (smtcount > 0) {
22141  printf(" Smoothed %d Steiner points.\n", smtcount);
22142  }
22143  }
22144  } // -Y2
22145 
22146  subvertstack->restart();
22147 
22148  return 1;
22149 }
22150 
22152 // //
22153 // recoverboundary() Recover segments and facets. //
22154 // //
22156 
22157 void tetgenmesh::recoverboundary(clock_t& tv)
22158 {
22159  arraypool *misseglist, *misshlist;
22160  arraypool *bdrysteinerptlist;
22161  face searchsh, *parysh;
22162  face searchseg, *paryseg;
22163  point rempt, *parypt;
22164  long ms; // The number of missing segments/subfaces.
22165  int nit; // The number of iterations.
22166  int s, i;
22167 
22168  // Counters.
22169  long bak_segref_count, bak_facref_count, bak_volref_count;
22170 
22171  if (!b->quiet) {
22172  printf("Recovering boundaries...\n");
22173  }
22174 
22175 
22176  if (b->verbose) {
22177  printf(" Recovering segments.\n");
22178  }
22179 
22180  // Segments will be introduced.
22181  checksubsegflag = 1;
22182 
22183  misseglist = new arraypool(sizeof(face), 8);
22184  bdrysteinerptlist = new arraypool(sizeof(point), 8);
22185 
22186  // In random order.
22187  subsegs->traversalinit();
22188  for (i = 0; i < subsegs->items; i++) {
22189  s = randomnation(i + 1);
22190  // Move the s-th seg to the i-th.
22191  subsegstack->newindex((void **) &paryseg);
22192  *paryseg = * (face *) fastlookup(subsegstack, s);
22193  // Put i-th seg to be the s-th.
22194  searchseg.sh = shellfacetraverse(subsegs);
22195  paryseg = (face *) fastlookup(subsegstack, s);
22196  *paryseg = searchseg;
22197  }
22198 
22199  // The init number of missing segments.
22200  ms = subsegs->items;
22201  nit = 0;
22202  if (b->fliplinklevel < 0) {
22203  autofliplinklevel = 1; // Init value.
22204  }
22205 
22206  // First, trying to recover segments by only doing flips.
22207  while (1) {
22208  recoversegments(misseglist, 0, 0);
22209 
22210  if (misseglist->objects > 0) {
22211  if (b->fliplinklevel >= 0) {
22212  break;
22213  } else {
22214  if (misseglist->objects >= ms) {
22215  nit++;
22216  if (nit >= 3) {
22217  //break;
22218  // Do the last round with unbounded flip link level.
22219  b->fliplinklevel = 100000;
22220  }
22221  } else {
22222  ms = misseglist->objects;
22223  if (nit > 0) {
22224  nit--;
22225  }
22226  }
22227  for (i = 0; i < misseglist->objects; i++) {
22228  subsegstack->newindex((void **) &paryseg);
22229  *paryseg = * (face *) fastlookup(misseglist, i);
22230  }
22231  misseglist->restart();
22232  autofliplinklevel+=b->fliplinklevelinc;
22233  }
22234  } else {
22235  // All segments are recovered.
22236  break;
22237  }
22238  } // while (1)
22239 
22240  if (b->verbose) {
22241  printf(" %ld (%ld) segments are recovered (missing).\n",
22242  subsegs->items - misseglist->objects, misseglist->objects);
22243  }
22244 
22245  if (misseglist->objects > 0) {
22246  // Second, trying to recover segments by doing more flips (fullsearch).
22247  while (misseglist->objects > 0) {
22248  ms = misseglist->objects;
22249  for (i = 0; i < misseglist->objects; i++) {
22250  subsegstack->newindex((void **) &paryseg);
22251  *paryseg = * (face *) fastlookup(misseglist, i);
22252  }
22253  misseglist->restart();
22254 
22255  recoversegments(misseglist, 1, 0);
22256 
22257  if (misseglist->objects < ms) {
22258  // The number of missing segments is reduced.
22259  continue;
22260  } else {
22261  break;
22262  }
22263  }
22264  if (b->verbose) {
22265  printf(" %ld (%ld) segments are recovered (missing).\n",
22266  subsegs->items - misseglist->objects, misseglist->objects);
22267  }
22268  }
22269 
22270  if (misseglist->objects > 0) {
22271  // Third, trying to recover segments by doing more flips (fullsearch)
22272  // and adding Steiner points in the volume.
22273  while (misseglist->objects > 0) {
22274  ms = misseglist->objects;
22275  for (i = 0; i < misseglist->objects; i++) {
22276  subsegstack->newindex((void **) &paryseg);
22277  *paryseg = * (face *) fastlookup(misseglist, i);
22278  }
22279  misseglist->restart();
22280 
22281  recoversegments(misseglist, 1, 1);
22282 
22283  if (misseglist->objects < ms) {
22284  // The number of missing segments is reduced.
22285  continue;
22286  } else {
22287  break;
22288  }
22289  }
22290  if (b->verbose) {
22291  printf(" Added %ld Steiner points in volume.\n", st_volref_count);
22292  }
22293  }
22294 
22295  if (misseglist->objects > 0) {
22296  // Last, trying to recover segments by doing more flips (fullsearch),
22297  // and adding Steiner points in the volume, and splitting segments.
22298  long bak_inpoly_count = st_volref_count; //st_inpoly_count;
22299  for (i = 0; i < misseglist->objects; i++) {
22300  subsegstack->newindex((void **) &paryseg);
22301  *paryseg = * (face *) fastlookup(misseglist, i);
22302  }
22303  misseglist->restart();
22304 
22305  recoversegments(misseglist, 1, 2);
22306 
22307  if (b->verbose) {
22308  printf(" Added %ld Steiner points in segments.\n", st_segref_count);
22309  if (st_volref_count > bak_inpoly_count) {
22310  printf(" Added another %ld Steiner points in volume.\n",
22311  st_volref_count - bak_inpoly_count);
22312  }
22313  }
22314  }
22315 
22316 
22317  if (st_segref_count > 0) {
22318  // Try to remove the Steiner points added in segments.
22319  bak_segref_count = st_segref_count;
22320  bak_volref_count = st_volref_count;
22321  for (i = 0; i < subvertstack->objects; i++) {
22322  // Get the Steiner point.
22323  parypt = (point *) fastlookup(subvertstack, i);
22324  rempt = *parypt;
22325  if (!removevertexbyflips(rempt)) {
22326  // Save it in list.
22327  bdrysteinerptlist->newindex((void **) &parypt);
22328  *parypt = rempt;
22329  }
22330  }
22331  if (b->verbose) {
22332  if (st_segref_count < bak_segref_count) {
22333  if (bak_volref_count < st_volref_count) {
22334  printf(" Suppressed %ld Steiner points in segments.\n",
22335  st_volref_count - bak_volref_count);
22336  }
22337  if ((st_segref_count + (st_volref_count - bak_volref_count)) <
22338  bak_segref_count) {
22339  printf(" Removed %ld Steiner points in segments.\n",
22340  bak_segref_count -
22341  (st_segref_count + (st_volref_count - bak_volref_count)));
22342  }
22343  }
22344  }
22345  subvertstack->restart();
22346  }
22347 
22348 
22349  tv = clock();
22350 
22351  if (b->verbose) {
22352  printf(" Recovering facets.\n");
22353  }
22354 
22355  // Subfaces will be introduced.
22356  checksubfaceflag = 1;
22357 
22358  misshlist = new arraypool(sizeof(face), 8);
22359 
22360  // Randomly order the subfaces.
22361  subfaces->traversalinit();
22362  for (i = 0; i < subfaces->items; i++) {
22363  s = randomnation(i + 1);
22364  // Move the s-th subface to the i-th.
22365  subfacstack->newindex((void **) &parysh);
22366  *parysh = * (face *) fastlookup(subfacstack, s);
22367  // Put i-th subface to be the s-th.
22368  searchsh.sh = shellfacetraverse(subfaces);
22369  parysh = (face *) fastlookup(subfacstack, s);
22370  *parysh = searchsh;
22371  }
22372 
22373  ms = subfaces->items;
22374  nit = 0;
22375  b->fliplinklevel = -1; // Init.
22376  if (b->fliplinklevel < 0) {
22377  autofliplinklevel = 1; // Init value.
22378  }
22379 
22380  while (1) {
22381  recoversubfaces(misshlist, 0);
22382 
22383  if (misshlist->objects > 0) {
22384  if (b->fliplinklevel >= 0) {
22385  break;
22386  } else {
22387  if (misshlist->objects >= ms) {
22388  nit++;
22389  if (nit >= 3) {
22390  //break;
22391  // Do the last round with unbounded flip link level.
22392  b->fliplinklevel = 100000;
22393  }
22394  } else {
22395  ms = misshlist->objects;
22396  if (nit > 0) {
22397  nit--;
22398  }
22399  }
22400  for (i = 0; i < misshlist->objects; i++) {
22401  subfacstack->newindex((void **) &parysh);
22402  *parysh = * (face *) fastlookup(misshlist, i);
22403  }
22404  misshlist->restart();
22405  autofliplinklevel+=b->fliplinklevelinc;
22406  }
22407  } else {
22408  // All subfaces are recovered.
22409  break;
22410  }
22411  } // while (1)
22412 
22413  if (b->verbose) {
22414  printf(" %ld (%ld) subfaces are recovered (missing).\n",
22415  subfaces->items - misshlist->objects, misshlist->objects);
22416  }
22417 
22418  if (misshlist->objects > 0) {
22419  // There are missing subfaces. Add Steiner points.
22420  for (i = 0; i < misshlist->objects; i++) {
22421  subfacstack->newindex((void **) &parysh);
22422  *parysh = * (face *) fastlookup(misshlist, i);
22423  }
22424  misshlist->restart();
22425 
22426  recoversubfaces(NULL, 1);
22427 
22428  if (b->verbose) {
22429  printf(" Added %ld Steiner points in facets.\n", st_facref_count);
22430  }
22431  }
22432 
22433 
22434  if (st_facref_count > 0) {
22435  // Try to remove the Steiner points added in facets.
22436  bak_facref_count = st_facref_count;
22437  for (i = 0; i < subvertstack->objects; i++) {
22438  // Get the Steiner point.
22439  parypt = (point *) fastlookup(subvertstack, i);
22440  rempt = *parypt;
22441  if (!removevertexbyflips(*parypt)) {
22442  // Save it in list.
22443  bdrysteinerptlist->newindex((void **) &parypt);
22444  *parypt = rempt;
22445  }
22446  }
22447  if (b->verbose) {
22448  if (st_facref_count < bak_facref_count) {
22449  printf(" Removed %ld Steiner points in facets.\n",
22450  bak_facref_count - st_facref_count);
22451  }
22452  }
22453  subvertstack->restart();
22454  }
22455 
22456 
22457  if (bdrysteinerptlist->objects > 0) {
22458  if (b->verbose) {
22459  printf(" %ld Steiner points remained in boundary.\n",
22460  bdrysteinerptlist->objects);
22461  }
22462  } // if
22463 
22464 
22465  // Accumulate the dynamic memory.
22466  totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
22467  bdrysteinerptlist->totalmemory);
22468 
22469  delete bdrysteinerptlist;
22470  delete misseglist;
22471  delete misshlist;
22472 }
22473 
22477 
22478 
22482 
22484 // //
22485 // carveholes() Remove tetrahedra not in the mesh domain. //
22486 // //
22488 
22489 
22490 void tetgenmesh::carveholes()
22491 {
22492  arraypool *tetarray, *hullarray;
22493  triface tetloop, neightet, *parytet, *parytet1;
22494  triface *regiontets = NULL;
22495  face checksh, *parysh;
22496  face checkseg;
22497  point ptloop, *parypt;
22498  int t1ver;
22499  int i, j, k;
22500 
22501  if (!b->quiet) {
22502  if (b->convex) {
22503  printf("Marking exterior tetrahedra ...\n");
22504  } else {
22505  printf("Removing exterior tetrahedra ...\n");
22506  }
22507  }
22508 
22509  // Initialize the pool of exterior tets.
22510  tetarray = new arraypool(sizeof(triface), 10);
22511  hullarray = new arraypool(sizeof(triface), 10);
22512 
22513  // Collect unprotected tets and hull tets.
22514  tetrahedrons->traversalinit();
22515  tetloop.ver = 11; // The face opposite to dummypoint.
22516  tetloop.tet = alltetrahedrontraverse();
22517  while (tetloop.tet != (tetrahedron *) NULL) {
22518  if (ishulltet(tetloop)) {
22519  // Is this side protected by a subface?
22520  if (!issubface(tetloop)) {
22521  // Collect an unprotected hull tet and tet.
22522  infect(tetloop);
22523  hullarray->newindex((void **) &parytet);
22524  *parytet = tetloop;
22525  // tetloop's face number is 11 & 3 = 3.
22526  decode(tetloop.tet[3], neightet);
22527  if (!infected(neightet)) {
22528  infect(neightet);
22529  tetarray->newindex((void **) &parytet);
22530  *parytet = neightet;
22531  }
22532  }
22533  }
22534  tetloop.tet = alltetrahedrontraverse();
22535  }
22536 
22537  if (in->numberofholes > 0) {
22538  // Mark as infected any tets inside volume holes.
22539  for (i = 0; i < 3 * in->numberofholes; i += 3) {
22540  // Search a tet containing the i-th hole point.
22541  neightet.tet = NULL;
22542  randomsample(&(in->holelist[i]), &neightet);
22543  if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
22544  // The tet 'neightet' contain this point.
22545  if (!infected(neightet)) {
22546  infect(neightet);
22547  tetarray->newindex((void **) &parytet);
22548  *parytet = neightet;
22549  // Add its adjacent tet if it is not protected.
22550  if (!issubface(neightet)) {
22551  decode(neightet.tet[neightet.ver & 3], tetloop);
22552  if (!infected(tetloop)) {
22553  infect(tetloop);
22554  if (ishulltet(tetloop)) {
22555  hullarray->newindex((void **) &parytet);
22556  } else {
22557  tetarray->newindex((void **) &parytet);
22558  }
22559  *parytet = tetloop;
22560  }
22561  }
22562  else {
22563  // It is protected. Check if its adjacent tet is a hull tet.
22564  decode(neightet.tet[neightet.ver & 3], tetloop);
22565  if (ishulltet(tetloop)) {
22566  // It is hull tet, add it into the list. Moreover, the subface
22567  // is dead, i.e., both sides are in exterior.
22568  if (!infected(tetloop)) {
22569  infect(tetloop);
22570  hullarray->newindex((void **) &parytet);
22571  *parytet = tetloop;
22572  }
22573  }
22574  if (infected(tetloop)) {
22575  // Both sides of this subface are in exterior.
22576  tspivot(neightet, checksh);
22577  sinfect(checksh); // Only queue it once.
22578  subfacstack->newindex((void **) &parysh);
22579  *parysh = checksh;
22580  }
22581  }
22582  } // if (!infected(neightet))
22583  } else {
22584  // A hole point locates outside of the convex hull.
22585  if (!b->quiet) {
22586  printf("Warning: The %d-th hole point ", i/3 + 1);
22587  printf("lies outside the convex hull.\n");
22588  }
22589  }
22590  } // i
22591  } // if (in->numberofholes > 0)
22592 
22593  if (b->hole_mesh && (b->hole_mesh_filename[0] != 0)) {
22594  // A hole mesh (***.ele) is given.
22595  //enum tetgenbehavior::objecttype object;
22596  char filebasename[256];
22597  strcpy(filebasename, b->hole_mesh_filename);
22598  //object = tetgenbehavior::MESH;
22599  if (!strcmp(&filebasename[strlen(filebasename) - 4], ".ele")) {
22600  filebasename[strlen(filebasename) - 4] = '\0';
22601  //object = tetgenbehavior::MESH;
22602  }
22603  bool hole_mesh_loaded = false;
22604  tetgenio io;
22605  if (io.load_node(filebasename)) {
22606  if (io.load_tet(filebasename)) {
22607  hole_mesh_loaded = true;
22608  }
22609  }
22610  if (hole_mesh_loaded) {
22611  if (b->verbose) {
22612  printf(" Adding hole tets from the mesh %s\n", b->hole_mesh_filename);
22613  }
22614  int count = 0, hcount = 0, scount = 0;
22615  int shift = io.firstnumber > 0 ? -1 : 0;
22616  double *p1, *p2, *p3, *p4;
22617  double searchpt[3];
22618  for (i = 0; i < io.numberoftetrahedra; i++) {
22619  int *idx = &(io.tetrahedronlist[i * 4]);
22620  p1 = &(io.pointlist[(idx[0]+shift)*3]);
22621  p2 = &(io.pointlist[(idx[1]+shift)*3]);
22622  p3 = &(io.pointlist[(idx[2]+shift)*3]);
22623  p4 = &(io.pointlist[(idx[3]+shift)*3]);
22624  for (j = 0; j < 3; j++) {
22625  searchpt[j] = (p1[j]+p2[j]+p3[j]+p4[j])/4.;
22626  }
22627  // Search the point.
22628  neightet.tet = NULL;
22629  if (locate(searchpt, &neightet) != OUTSIDE) {
22630  // The tet 'neightet' contain this point.
22631  if (!infected(neightet)) {
22632  infect(neightet);
22633  tetarray->newindex((void **) &parytet);
22634  *parytet = neightet;
22635  count++;
22636  // Add its adjacent tet if it is not protected.
22637  if (!issubface(neightet)) {
22638  decode(neightet.tet[neightet.ver & 3], tetloop);
22639  if (!infected(tetloop)) {
22640  infect(tetloop);
22641  if (ishulltet(tetloop)) {
22642  hullarray->newindex((void **) &parytet);
22643  hcount++;
22644  } else {
22645  tetarray->newindex((void **) &parytet);
22646  count++;
22647  }
22648  *parytet = tetloop;
22649  }
22650  }
22651  else {
22652  // It is protected. Check if its adjacent tet is a hull tet.
22653  decode(neightet.tet[neightet.ver & 3], tetloop);
22654  if (ishulltet(tetloop)) {
22655  // It is hull tet, add it into the list. Moreover, the subface
22656  // is dead, i.e., both sides are in exterior.
22657  if (!infected(tetloop)) {
22658  infect(tetloop);
22659  hullarray->newindex((void **) &parytet);
22660  *parytet = tetloop;
22661  hcount++;
22662  }
22663  }
22664  if (infected(tetloop)) {
22665  // Both sides of this subface are in exterior.
22666  tspivot(neightet, checksh);
22667  sinfect(checksh); // Only queue it once.
22668  subfacstack->newindex((void **) &parysh);
22669  *parysh = checksh;
22670  scount++;
22671  }
22672  }
22673  }
22674  }
22675  } // i
22676  if (b->verbose) {
22677  printf(" Added %d hole tets, %d hull tet, %d hole subfaces\n",
22678  count, hcount, scount);
22679  }
22680  } // if (hole_mesh_loaded)
22681  }
22682 
22683  if (b->regionattrib && (in->numberofregions > 0)) { // -A option.
22684  // Record the tetrahedra that contains the region points for assigning
22685  // region attributes after the holes have been carved.
22686  regiontets = new triface[in->numberofregions];
22687  // Mark as marktested any tetrahedra inside volume regions.
22688  for (i = 0; i < 5 * in->numberofregions; i += 5) {
22689  // Search a tet containing the i-th region point.
22690  neightet.tet = NULL;
22691  randomsample(&(in->regionlist[i]), &neightet);
22692  if (locate(&(in->regionlist[i]), &neightet) != OUTSIDE) {
22693  regiontets[i/5] = neightet;
22694  } else {
22695  if (!b->quiet) {
22696  printf("Warning: The %d-th region point ", i/5+1);
22697  printf("lies outside the convex hull.\n");
22698  }
22699  regiontets[i/5].tet = NULL;
22700  }
22701  }
22702  }
22703 
22704  // Collect all exterior tets (in concave place and in holes).
22705  for (i = 0; i < tetarray->objects; i++) {
22706  parytet = (triface *) fastlookup(tetarray, i);
22707  j = (parytet->ver & 3); // j is the current face number.
22708  // Check the other three adjacent tets.
22709  for (k = 1; k < 4; k++) {
22710  decode(parytet->tet[(j + k) % 4], neightet);
22711  // neightet may be a hull tet.
22712  if (!infected(neightet)) {
22713  // Is neightet protected by a subface.
22714  if (!issubface(neightet)) {
22715  // Not proected. Collect it. (It must not be a hull tet).
22716  infect(neightet);
22717  tetarray->newindex((void **) &parytet1);
22718  *parytet1 = neightet;
22719  } else {
22720  // Protected. Check if it is a hull tet.
22721  if (ishulltet(neightet)) {
22722  // A hull tet. Collect it.
22723  infect(neightet);
22724  hullarray->newindex((void **) &parytet1);
22725  *parytet1 = neightet;
22726  // Both sides of this subface are exterior.
22727  tspivot(neightet, checksh);
22728  // Queue this subface (to be deleted later).
22729  sinfect(checksh); // Only queue it once.
22730  subfacstack->newindex((void **) &parysh);
22731  *parysh = checksh;
22732  }
22733  }
22734  } else {
22735  // Both sides of this face are in exterior.
22736  // If there is a subface. It should be collected.
22737  if (issubface(neightet)) {
22738  tspivot(neightet, checksh);
22739  if (!sinfected(checksh)) {
22740  sinfect(checksh);
22741  subfacstack->newindex((void **) &parysh);
22742  *parysh = checksh;
22743  }
22744  }
22745  }
22746  } // j, k
22747  } // i
22748 
22749  if (b->regionattrib && (in->numberofregions > 0)) {
22750  // Re-check saved region tets to see if they lie outside.
22751  for (i = 0; i < in->numberofregions; i++) {
22752  if (infected(regiontets[i])) {
22753  if (b->verbose) {
22754  printf("Warning: The %d-th region point ", i+1);
22755  printf("lies in the exterior of the domain.\n");
22756  }
22757  regiontets[i].tet = NULL;
22758  }
22759  }
22760  }
22761 
22762  // Collect vertices which point to infected tets. These vertices
22763  // may get deleted after the removal of exterior tets.
22764  // If -Y1 option is used, collect all Steiner points for removal.
22765  // The lists 'cavetetvertlist' and 'subvertstack' are re-used.
22766  points->traversalinit();
22767  ptloop = pointtraverse();
22768  while (ptloop != NULL) {
22769  if ((pointtype(ptloop) != UNUSEDVERTEX) &&
22770  (pointtype(ptloop) != DUPLICATEDVERTEX)) {
22771  decode(point2tet(ptloop), neightet);
22772  if (infected(neightet)) {
22773  cavetetvertlist->newindex((void **) &parypt);
22774  *parypt = ptloop;
22775  }
22776  if (b->nobisect && (b->supsteiner_level > 0)) { // -Y/1
22777  // Queue it if it is a Steiner point.
22778  if (pointmark(ptloop) >
22779  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22780  subvertstack->newindex((void **) &parypt);
22781  *parypt = ptloop;
22782  }
22783  }
22784  }
22785  ptloop = pointtraverse();
22786  }
22787 
22788  if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
22789  // Remove exterior tets. Hull tets are updated.
22790  arraypool *newhullfacearray;
22791  triface hulltet, casface;
22792  face segloop, *paryseg;
22793  point pa, pb, pc;
22794  long delsegcount = 0l;
22795 
22796  // Collect segments which point to infected tets. Some segments
22797  // may get deleted after the removal of exterior tets.
22798  subsegs->traversalinit();
22799  segloop.sh = shellfacetraverse(subsegs);
22800  while (segloop.sh != NULL) {
22801  sstpivot1(segloop, neightet);
22802  if (infected(neightet)) {
22803  subsegstack->newindex((void **) &paryseg);
22804  *paryseg = segloop;
22805  }
22806  segloop.sh = shellfacetraverse(subsegs);
22807  }
22808 
22809  newhullfacearray = new arraypool(sizeof(triface), 10);
22810 
22811  // Create and save new hull tets.
22812  for (i = 0; i < tetarray->objects; i++) {
22813  parytet = (triface *) fastlookup(tetarray, i);
22814  for (j = 0; j < 4; j++) {
22815  decode(parytet->tet[j], tetloop);
22816  if (!infected(tetloop)) {
22817  // Found a new hull face (must be a subface).
22818  tspivot(tetloop, checksh);
22819  maketetrahedron(&hulltet);
22820  pa = org(tetloop);
22821  pb = dest(tetloop);
22822  pc = apex(tetloop);
22823  setvertices(hulltet, pb, pa, pc, dummypoint);
22824  bond(tetloop, hulltet);
22825  // Update the subface-to-tet map.
22826  sesymself(checksh);
22827  tsbond(hulltet, checksh);
22828  // Update the segment-to-tet map.
22829  for (k = 0; k < 3; k++) {
22830  if (issubseg(tetloop)) {
22831  tsspivot1(tetloop, checkseg);
22832  tssbond1(hulltet, checkseg);
22833  sstbond1(checkseg, hulltet);
22834  }
22835  enextself(tetloop);
22836  eprevself(hulltet);
22837  }
22838  // Update the point-to-tet map.
22839  setpoint2tet(pa, (tetrahedron) tetloop.tet);
22840  setpoint2tet(pb, (tetrahedron) tetloop.tet);
22841  setpoint2tet(pc, (tetrahedron) tetloop.tet);
22842  // Save the exterior tet at this hull face. It still holds pointer
22843  // to the adjacent interior tet. Use it to connect new hull tets.
22844  newhullfacearray->newindex((void **) &parytet1);
22845  parytet1->tet = parytet->tet;
22846  parytet1->ver = j;
22847  } // if (!infected(tetloop))
22848  } // j
22849  } // i
22850 
22851  // Connect new hull tets.
22852  for (i = 0; i < newhullfacearray->objects; i++) {
22853  parytet = (triface *) fastlookup(newhullfacearray, i);
22854  fsym(*parytet, neightet);
22855  // Get the new hull tet.
22856  fsym(neightet, hulltet);
22857  for (j = 0; j < 3; j++) {
22858  esym(hulltet, casface);
22859  if (casface.tet[casface.ver & 3] == NULL) {
22860  // Since the boundary of the domain may not be a manifold, we
22861  // find the adjacent hull face by traversing the tets in the
22862  // exterior (which are all infected tets).
22863  neightet = *parytet;
22864  while (1) {
22865  fnextself(neightet);
22866  if (!infected(neightet)) break;
22867  }
22868  if (!ishulltet(neightet)) {
22869  // An interior tet. Get the new hull tet.
22870  fsymself(neightet);
22871  esymself(neightet);
22872  }
22873  // Bond them together.
22874  bond(casface, neightet);
22875  }
22876  enextself(hulltet);
22877  enextself(*parytet);
22878  } // j
22879  } // i
22880 
22881  if (subfacstack->objects > 0l) {
22882  // Remove all subfaces which do not attach to any tetrahedron.
22883  // Segments which are not attached to any subfaces and tets
22884  // are deleted too.
22885  face casingout, casingin;
22886 
22887  for (i = 0; i < subfacstack->objects; i++) {
22888  parysh = (face *) fastlookup(subfacstack, i);
22889  if (i == 0) {
22890  if (b->verbose) {
22891  printf("Warning: Removed an exterior face (%d, %d, %d) #%d\n",
22892  pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
22893  pointmark(sapex(*parysh)), shellmark(*parysh));
22894  }
22895  }
22896  // Dissolve this subface from face links.
22897  for (j = 0; j < 3; j++) {
22898  spivot(*parysh, casingout);
22899  sspivot(*parysh, checkseg);
22900  if (casingout.sh != NULL) {
22901  casingin = casingout;
22902  while (1) {
22903  spivot(casingin, checksh);
22904  if (checksh.sh == parysh->sh) break;
22905  casingin = checksh;
22906  }
22907  if (casingin.sh != casingout.sh) {
22908  // Update the link: ... -> casingin -> casingout ->...
22909  sbond1(casingin, casingout);
22910  } else {
22911  // Only one subface at this edge is left.
22912  sdissolve(casingout);
22913  }
22914  if (checkseg.sh != NULL) {
22915  // Make sure the segment does not connect to a dead one.
22916  ssbond(casingout, checkseg);
22917  }
22918  } else {
22919  if (checkseg.sh != NULL) {
22920  //if (checkseg.sh[3] != NULL) {
22921  if (delsegcount == 0) {
22922  if (b->verbose) {
22923  printf("Warning: Removed an exterior segment (%d, %d) #%d\n",
22924  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
22925  shellmark(checkseg));
22926  }
22927  }
22928  shellfacedealloc(subsegs, checkseg.sh);
22929  delsegcount++;
22930  }
22931  }
22932  senextself(*parysh);
22933  } // j
22934  // Delete this subface.
22935  shellfacedealloc(subfaces, parysh->sh);
22936  } // i
22937  if (b->verbose) {
22938  printf(" Deleted %ld subfaces.\n", subfacstack->objects);
22939  }
22940  subfacstack->restart();
22941  } // if (subfacstack->objects > 0l)
22942 
22943  if (subsegstack->objects > 0l) {
22944  for (i = 0; i < subsegstack->objects; i++) {
22945  paryseg = (face *) fastlookup(subsegstack, i);
22946  if (paryseg->sh && (paryseg->sh[3] != NULL)) {
22947  sstpivot1(*paryseg, neightet);
22948  if (infected(neightet)) {
22949  if (b->verbose) {
22950  printf("Warning: Removed an exterior segment (%d, %d) #%d\n",
22951  pointmark(sorg(*paryseg)), pointmark(sdest(*paryseg)),
22952  shellmark(*paryseg));
22953  }
22954  shellfacedealloc(subsegs, paryseg->sh);
22955  delsegcount++;
22956  }
22957  }
22958  }
22959  subsegstack->restart();
22960  } // if (subsegstack->objects > 0l)
22961 
22962  if (delsegcount > 0) {
22963  if (b->verbose) {
22964  printf(" Deleted %ld segments.\n", delsegcount);
22965  }
22966  }
22967 
22968  if (cavetetvertlist->objects > 0l) {
22969  // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
22970  long delvertcount = unuverts;
22971  long delsteinercount = 0l;
22972 
22973  for (i = 0; i < cavetetvertlist->objects; i++) {
22974  parypt = (point *) fastlookup(cavetetvertlist, i);
22975  decode(point2tet(*parypt), neightet);
22976  if (infected(neightet)) {
22977  // Found an exterior vertex.
22978  if (pointmark(*parypt) >
22979  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22980  // A Steiner point.
22981  if (pointtype(*parypt) == FREESEGVERTEX) {
22982  st_segref_count--;
22983  } else if (pointtype(*parypt) == FREEFACETVERTEX) {
22984  st_facref_count--;
22985  } else {
22986  st_volref_count--;
22987  }
22988  delsteinercount++;
22989  if (steinerleft > 0) steinerleft++;
22990  }
22991  setpointtype(*parypt, UNUSEDVERTEX);
22992  unuverts++;
22993  }
22994  }
22995 
22996  if (b->verbose) {
22997  if (unuverts > delvertcount) {
22998  if (delsteinercount > 0l) {
22999  if (unuverts > (delvertcount + delsteinercount)) {
23000  printf(" Removed %ld exterior input vertices.\n",
23001  unuverts - delvertcount - delsteinercount);
23002  }
23003  printf(" Removed %ld exterior Steiner vertices.\n",
23004  delsteinercount);
23005  } else {
23006  printf(" Removed %ld exterior input vertices.\n",
23007  unuverts - delvertcount);
23008  }
23009  }
23010  }
23011  cavetetvertlist->restart();
23012  // Comment: 'subvertstack' will be cleaned in routine
23013  // suppresssteinerpoints().
23014  } // if (cavetetvertlist->objects > 0l)
23015 
23016  // Update the hull size.
23017  hullsize += (newhullfacearray->objects - hullarray->objects);
23018 
23019  // Delete all exterior tets and old hull tets.
23020  for (i = 0; i < tetarray->objects; i++) {
23021  parytet = (triface *) fastlookup(tetarray, i);
23022  tetrahedrondealloc(parytet->tet);
23023  }
23024  tetarray->restart();
23025 
23026  for (i = 0; i < hullarray->objects; i++) {
23027  parytet = (triface *) fastlookup(hullarray, i);
23028  tetrahedrondealloc(parytet->tet);
23029  }
23030  hullarray->restart();
23031 
23032  delete newhullfacearray;
23033  } // if (!b->convex && (tetarray->objects > 0l))
23034 
23035  if (b->convex && (tetarray->objects > 0l)) { // With -c option
23036  // In this case, all exterior tets get a region marker '-1'.
23037  int attrnum = numelemattrib - 1;
23038 
23039  for (i = 0; i < tetarray->objects; i++) {
23040  parytet = (triface *) fastlookup(tetarray, i);
23041  setelemattribute(parytet->tet, attrnum, -1);
23042  }
23043  tetarray->restart();
23044 
23045  for (i = 0; i < hullarray->objects; i++) {
23046  parytet = (triface *) fastlookup(hullarray, i);
23047  uninfect(*parytet);
23048  }
23049  hullarray->restart();
23050 
23051  if (subfacstack->objects > 0l) {
23052  for (i = 0; i < subfacstack->objects; i++) {
23053  parysh = (face *) fastlookup(subfacstack, i);
23054  suninfect(*parysh);
23055  }
23056  subfacstack->restart();
23057  }
23058 
23059  if (cavetetvertlist->objects > 0l) {
23060  cavetetvertlist->restart();
23061  }
23062  } // if (b->convex && (tetarray->objects > 0l))
23063 
23064  if (b->regionattrib) { // With -A option.
23065  if (!b->quiet) {
23066  printf("Spreading region attributes.\n");
23067  }
23068  REAL volume;
23069  int attr, maxattr = 0; // Choose a small number here.
23070  int attrnum = numelemattrib - 1;
23071  // Comment: The element region marker is at the end of the list of
23072  // the element attributes.
23073  int regioncount = 0;
23074 
23075  // If has user-defined region attributes.
23076  if (in->numberofregions > 0) {
23077  // Spread region attributes.
23078  for (i = 0; i < 5 * in->numberofregions; i += 5) {
23079  if (regiontets[i/5].tet != NULL) {
23080  attr = (int) in->regionlist[i + 3];
23081  if (attr > maxattr) {
23082  maxattr = attr;
23083  }
23084  volume = in->regionlist[i + 4];
23085  tetarray->restart(); // Re-use this array.
23086  infect(regiontets[i/5]);
23087  tetarray->newindex((void **) &parytet);
23088  *parytet = regiontets[i/5];
23089  // Collect and set attrs for all tets of this region.
23090  for (j = 0; j < tetarray->objects; j++) {
23091  parytet = (triface *) fastlookup(tetarray, j);
23092  tetloop = *parytet;
23093  setelemattribute(tetloop.tet, attrnum, attr);
23094  if (b->varvolume) { // If has -a option.
23095  setvolumebound(tetloop.tet, volume);
23096  }
23097  for (k = 0; k < 4; k++) {
23098  decode(tetloop.tet[k], neightet);
23099  // Is the adjacent already checked?
23100  if (!infected(neightet)) {
23101  // Is this side protected by a subface?
23102  if (!issubface(neightet)) {
23103  infect(neightet);
23104  tetarray->newindex((void **) &parytet);
23105  *parytet = neightet;
23106  }
23107  }
23108  } // k
23109  } // j
23110  regioncount++;
23111  } // if (regiontets[i/5].tet != NULL)
23112  } // i
23113  }
23114 
23115  // Set attributes for all tetrahedra.
23116  attr = maxattr + 1;
23117  tetrahedrons->traversalinit();
23118  tetloop.tet = tetrahedrontraverse();
23119  while (tetloop.tet != (tetrahedron *) NULL) {
23120  if (!infected(tetloop)) {
23121  // An unmarked region.
23122  tetarray->restart(); // Re-use this array.
23123  infect(tetloop);
23124  tetarray->newindex((void **) &parytet);
23125  *parytet = tetloop;
23126  // Find and mark all tets.
23127  for (j = 0; j < tetarray->objects; j++) {
23128  parytet = (triface *) fastlookup(tetarray, j);
23129  tetloop = *parytet;
23130  setelemattribute(tetloop.tet, attrnum, attr);
23131  for (k = 0; k < 4; k++) {
23132  decode(tetloop.tet[k], neightet);
23133  // Is the adjacent tet already checked?
23134  if (!infected(neightet)) {
23135  // Is this side protected by a subface?
23136  if (!issubface(neightet)) {
23137  infect(neightet);
23138  tetarray->newindex((void **) &parytet);
23139  *parytet = neightet;
23140  }
23141  }
23142  } // k
23143  } // j
23144  attr++; // Increase the attribute.
23145  regioncount++;
23146  }
23147  tetloop.tet = tetrahedrontraverse();
23148  }
23149  // Until here, every tet has a region attribute.
23150 
23151  // Uninfect processed tets.
23152  tetrahedrons->traversalinit();
23153  tetloop.tet = tetrahedrontraverse();
23154  while (tetloop.tet != (tetrahedron *) NULL) {
23155  uninfect(tetloop);
23156  tetloop.tet = tetrahedrontraverse();
23157  }
23158 
23159  if (b->verbose) {
23160  //assert(regioncount > 0);
23161  if (regioncount > 1) {
23162  printf(" Found %d subdomains.\n", regioncount);
23163  } else {
23164  printf(" Found %d domain.\n", regioncount);
23165  }
23166  }
23167  } // if (b->regionattrib)
23168 
23169  if (regiontets != NULL) {
23170  delete [] regiontets;
23171  }
23172  delete tetarray;
23173  delete hullarray;
23174 
23175  if (!b->convex) { // No -c option
23176  // The mesh is non-convex now.
23177  nonconvex = 1;
23178 
23179  // Push all hull tets into 'flipstack'.
23180  tetrahedrons->traversalinit();
23181  tetloop.ver = 11; // The face opposite to dummypoint.
23182  tetloop.tet = alltetrahedrontraverse();
23183  while (tetloop.tet != (tetrahedron *) NULL) {
23184  if ((point) tetloop.tet[7] == dummypoint) {
23185  fsym(tetloop, neightet);
23186  flippush(flipstack, &neightet);
23187  }
23188  tetloop.tet = alltetrahedrontraverse();
23189  }
23190 
23191  flipconstraints fc;
23192  fc.enqflag = 2;
23193  long sliver_peel_count = lawsonflip3d(&fc);
23194 
23195  if (sliver_peel_count > 0l) {
23196  if (b->verbose) {
23197  printf(" Removed %ld hull slivers.\n", sliver_peel_count);
23198  }
23199  }
23200  unflipqueue->restart();
23201  } // if (!b->convex)
23202 }
23203 
23204 // [2018-07-30]
23205 // Search a face with given indices (i,j,k).
23206 // This function is only called when the default fast search fails.
23207 // It is possible when there are non-manifold edges on the hull.
23208 // On finish, tetloop return this face if it exists, otherwise, return 0.
23209 int tetgenmesh::search_face(point pi, point pj, point pk, triface &tetloop)
23210 {
23211  pinfect(pi);
23212  pinfect(pj);
23213  pinfect(pk);
23214 
23215  int t1ver;
23216  triface t, t1;
23217  point *pts, toppo;
23218  int pcount = 0;
23219 
23220  t.ver = t1.ver = 0;
23221  tetrahedrons->traversalinit();
23222  t.tet = tetrahedrontraverse();
23223  while (t.tet != NULL) {
23224  pts = (point *) t.tet;
23225  pcount = 0;
23226  if (pinfected(pts[4])) pcount++;
23227  if (pinfected(pts[5])) pcount++;
23228  if (pinfected(pts[6])) pcount++;
23229  if (pinfected(pts[7])) pcount++;
23230 
23231  if (pcount == 3) {
23232  // Found a tet containing this face.
23233  for (t.ver = 0; t.ver < 4; t.ver++) {
23234  toppo = oppo(t);
23235  if (!pinfected(toppo)) break;
23236  }
23237  int ii;
23238  for (ii = 0; ii < 3; ii++) {
23239  if (org(t) == pi) break;
23240  enextself(t);
23241  }
23242  if (dest(t) == pj) {
23243  } else {
23244  eprevself(t);
23245  fsymself(t);
23246  }
23247  break;
23248  }
23249  t.tet = tetrahedrontraverse();
23250  }
23251 
23252  puninfect(pi);
23253  puninfect(pj);
23254  puninfect(pk);
23255 
23256  if (t.tet != NULL) {
23257  tetloop = t;
23258  return 1;
23259  } else {
23260  return 0;
23261  }
23262 }
23263 
23264 int tetgenmesh::search_edge(point p0, point p1, triface &tetloop)
23265 {
23266  triface t;
23267  int ii;
23268 
23269  tetrahedrons->traversalinit();
23270  t.tet = tetrahedrontraverse();
23271  while (t.tet != NULL) {
23272  for (ii = 0; ii < 6; ii++) {
23273  t.ver = edge2ver[ii];
23274  if (((org(t) == p0) && (dest(t) == p1)) ||
23275  ((org(t) == p1) && (dest(t) == p0))) {
23276  // Found the tet.
23277  tetloop = t;
23278  return 1;
23279  }
23280  }
23281  t.tet = tetrahedrontraverse();
23282  }
23283 
23284  tetloop.tet = NULL;
23285  return 0;
23286 }
23287 
23289 // //
23290 // reconstructmesh() Reconstruct a tetrahedral mesh. //
23291 // //
23293 
23294 void tetgenmesh::reconstructmesh()
23295 {
23296  tetrahedron *ver2tetarray;
23297  point *idx2verlist;
23298  triface tetloop, checktet, prevchktet;
23299  triface hulltet, face1, face2;
23300  tetrahedron tptr;
23301  face subloop, neighsh, nextsh;
23302  face segloop;
23303  shellface sptr;
23304  point p[4], q[3];
23305  REAL ori, attrib, volume;
23306  REAL cosang_tol, cosang;
23307  REAL n1[3], n2[3];
23308  int eextras, marker = 0;
23309  int bondflag;
23310  int t1ver;
23311  int idx, i, j, k;
23312 
23313  if (!b->quiet) {
23314  printf("Reconstructing mesh ...\n");
23315  }
23316 
23317  if (b->convex) { // -c option.
23318  // Assume the mesh is convex. Exterior tets have region attribute -1.
23319  if (!(in->numberoftetrahedronattributes > 0)) {
23320  terminatetetgen(this, 2);
23321  }
23322  } else {
23323  // Assume the mesh is non-convex.
23324  nonconvex = 1;
23325  }
23326 
23327  // Create a map from indices to vertices.
23328  makeindex2pointmap(idx2verlist);
23329  // 'idx2verlist' has length 'in->numberofpoints + 1'.
23330  if (in->firstnumber == 1) {
23331  idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
23332  }
23333 
23334  // Allocate an array that maps each vertex to its adjacent tets.
23335  ver2tetarray = new tetrahedron[in->numberofpoints + 1];
23336  unuverts = in->numberofpoints; // All vertices are unused yet.
23337  //for (i = 0; i < in->numberofpoints + 1; i++) {
23338  for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
23339  ver2tetarray[i] = NULL;
23340  }
23341 
23342  // Create the tetrahedra and connect those that share a common face.
23343  for (i = 0; i < in->numberoftetrahedra; i++) {
23344  // Get the four vertices.
23345  idx = i * in->numberofcorners;
23346  for (j = 0; j < 4; j++) {
23347  p[j] = idx2verlist[in->tetrahedronlist[idx++]];
23348  if (pointtype(p[j]) == UNUSEDVERTEX) {
23349  setpointtype(p[j], VOLVERTEX); // initial type.
23350  unuverts--;
23351  }
23352  }
23353  // Check the orientation.
23354  ori = orient3d(p[0], p[1], p[2], p[3]);
23355  if (ori > 0.0) {
23356  // Swap the first two vertices.
23357  q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
23358  } else if (ori == 0.0) {
23359  if (!b->quiet) {
23360  printf("Warning: Tet #%d is degenerate.\n", i + in->firstnumber);
23361  }
23362  }
23363  // Create a new tetrahedron.
23364  maketetrahedron(&tetloop); // tetloop.ver = 11.
23365  setvertices(tetloop, p[0], p[1], p[2], p[3]);
23366  // Set element attributes if they exist.
23367  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
23368  idx = i * in->numberoftetrahedronattributes;
23369  attrib = in->tetrahedronattributelist[idx + j];
23370  setelemattribute(tetloop.tet, j, attrib);
23371  }
23372  // If -a switch is used (with no number follows) Set a volume
23373  // constraint if it exists.
23374  if (b->varvolume) {
23375  if (in->tetrahedronvolumelist != (REAL *) NULL) {
23376  volume = in->tetrahedronvolumelist[i];
23377  } else {
23378  volume = -1.0;
23379  }
23380  setvolumebound(tetloop.tet, volume);
23381  }
23382  // Try connecting this tet to others that share the common faces.
23383  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
23384  p[3] = oppo(tetloop);
23385  // Look for other tets having this vertex.
23386  idx = pointmark(p[3]);
23387  tptr = ver2tetarray[idx];
23388  // Link the current tet to the next one in the stack.
23389  tetloop.tet[8 + tetloop.ver] = tptr;
23390  // Push the current tet onto the stack.
23391  ver2tetarray[idx] = encode(tetloop);
23392  decode(tptr, checktet);
23393  if (checktet.tet != NULL) {
23394  p[0] = org(tetloop); // a
23395  p[1] = dest(tetloop); // b
23396  p[2] = apex(tetloop); // c
23397  prevchktet = tetloop;
23398  do {
23399  q[0] = org(checktet); // a'
23400  q[1] = dest(checktet); // b'
23401  q[2] = apex(checktet); // c'
23402  // Check the three faces at 'd' in 'checktet'.
23403  bondflag = 0;
23404  for (j = 0; j < 3; j++) {
23405  // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
23406  esym(checktet, face2);
23407  if (face2.tet[face2.ver & 3] == NULL) {
23408  k = ((j + 1) % 3);
23409  if (q[k] == p[0]) { // b', c', a' = a
23410  if (q[j] == p[1]) { // a', b', c' = b
23411  // [#,#,d] is matched to [b,a,d].
23412  esym(tetloop, face1);
23413  bond(face1, face2);
23414  bondflag++;
23415  }
23416  }
23417  if (q[k] == p[1]) { // b',c',a' = b
23418  if (q[j] == p[2]) { // a',b',c' = c
23419  // [#,#,d] is matched to [c,b,d].
23420  enext(tetloop, face1);
23421  esymself(face1);
23422  bond(face1, face2);
23423  bondflag++;
23424  }
23425  }
23426  if (q[k] == p[2]) { // b',c',a' = c
23427  if (q[j] == p[0]) { // a',b',c' = a
23428  // [#,#,d] is matched to [a,c,d].
23429  eprev(tetloop, face1);
23430  esymself(face1);
23431  bond(face1, face2);
23432  bondflag++;
23433  }
23434  }
23435  } else {
23436  bondflag++;
23437  }
23438  enextself(checktet);
23439  } // j
23440  // Go to the next tet in the link.
23441  tptr = checktet.tet[8 + checktet.ver];
23442  if (bondflag == 3) {
23443  // All three faces at d in 'checktet' have been connected.
23444  // It can be removed from the link.
23445  prevchktet.tet[8 + prevchktet.ver] = tptr;
23446  } else {
23447  // Bakup the previous tet in the link.
23448  prevchktet = checktet;
23449  }
23450  decode(tptr, checktet);
23451  } while (checktet.tet != NULL);
23452  } // if (checktet.tet != NULL)
23453  } // for (tetloop.ver = 0; ...
23454  } // i
23455 
23456  // Remember a tet of the mesh.
23457  recenttet = tetloop;
23458 
23459  // Create hull tets, create the point-to-tet map, and clean up the
23460  // temporary spaces used in each tet.
23461  hullsize = tetrahedrons->items;
23462 
23463  tetrahedrons->traversalinit();
23464  tetloop.tet = tetrahedrontraverse();
23465  while (tetloop.tet != (tetrahedron *) NULL) {
23466  tptr = encode(tetloop);
23467  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
23468  if (tetloop.tet[tetloop.ver] == NULL) {
23469  // Create a hull tet.
23470  maketetrahedron(&hulltet);
23471  p[0] = org(tetloop);
23472  p[1] = dest(tetloop);
23473  p[2] = apex(tetloop);
23474  setvertices(hulltet, p[1], p[0], p[2], dummypoint);
23475  bond(tetloop, hulltet);
23476  // Try connecting this to others that share common hull edges.
23477  for (j = 0; j < 3; j++) {
23478  fsym(hulltet, face2);
23479  while (1) {
23480  if (face2.tet == NULL) break;
23481  esymself(face2);
23482  if (apex(face2) == dummypoint) break;
23483  fsymself(face2);
23484  }
23485  if (face2.tet != NULL) {
23486  // Found an adjacent hull tet.
23487  esym(hulltet, face1);
23488  bond(face1, face2);
23489  }
23490  enextself(hulltet);
23491  }
23492  }
23493  // Create the point-to-tet map.
23494  setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
23495  // Clean the temporary used space.
23496  tetloop.tet[8 + tetloop.ver] = NULL;
23497  }
23498  tetloop.tet = tetrahedrontraverse();
23499  }
23500 
23501  hullsize = tetrahedrons->items - hullsize;
23502 
23503  // Subfaces will be inserted into the mesh.
23504  if (in->trifacelist != NULL) {
23505  // A .face file is given. It may contain boundary faces. Insert them.
23506  for (i = 0; i < in->numberoftrifaces; i++) {
23507  // Is it a subface?
23508  if (in->trifacemarkerlist != NULL) {
23509  marker = in->trifacemarkerlist[i];
23510  } else {
23511  // Face markers are not available. Assume all of them are subfaces.
23512  marker = -1; // The default marker.
23513  }
23514  if (marker != 0) {
23515  idx = i * 3;
23516  for (j = 0; j < 3; j++) {
23517  p[j] = idx2verlist[in->trifacelist[idx++]];
23518  }
23519  // Search the subface.
23520  bondflag = 0;
23521  neighsh.sh = NULL;
23522  // Make sure all vertices are in the mesh. Avoid crash.
23523  for (j = 0; j < 3; j++) {
23524  decode(point2tet(p[j]), checktet);
23525  if (checktet.tet == NULL) break;
23526  }
23527  if ((j == 3) && getedge(p[0], p[1], &checktet)) {
23528  tetloop = checktet;
23529  q[2] = apex(checktet);
23530  while (1) {
23531  if (apex(tetloop) == p[2]) {
23532  // Found the face.
23533  // Check if there exist a subface already?
23534  tspivot(tetloop, neighsh);
23535  if (neighsh.sh != NULL) {
23536  // Found a duplicated subface.
23537  // This happens when the mesh was generated by other mesher.
23538  bondflag = 0;
23539  } else {
23540  bondflag = 1;
23541  }
23542  break;
23543  }
23544  fnextself(tetloop);
23545  if (apex(tetloop) == q[2]) break;
23546  }
23547  }
23548  if (!bondflag) {
23549  if (neighsh.sh == NULL) {
23550  if (b->verbose > 1) {
23551  printf("Warning: Searching subface #%d [%d,%d,%d] mark=%d.\n",
23552  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
23553  pointmark(p[2]), marker);
23554  }
23555  // Search it globally.
23556  if (search_face(p[0], p[1], p[2], tetloop)) {
23557  bondflag = 1;
23558  }
23559  }
23560  }
23561  if (bondflag) {
23562  // Create a new subface.
23563  makeshellface(subfaces, &subloop);
23564  setshvertices(subloop, p[0], p[1], p[2]);
23565  // Create the point-to-subface map.
23566  sptr = sencode(subloop);
23567  for (j = 0; j < 3; j++) {
23568  setpointtype(p[j], FACETVERTEX); // initial type.
23569  setpoint2sh(p[j], sptr);
23570  }
23571  setshellmark(subloop, marker);
23572  // Insert the subface into the mesh.
23573  tsbond(tetloop, subloop);
23574  fsymself(tetloop);
23575  sesymself(subloop);
23576  tsbond(tetloop, subloop);
23577  } else {
23578  if (neighsh.sh != NULL) {
23579  // The subface already exists. Only set its mark.
23580  setshellmark(neighsh, marker);
23581  } else {
23582  if (!b->quiet) {
23583  printf("Warning: Subface #%d [%d,%d,%d] mark=%d is not found.\n",
23584  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
23585  pointmark(p[2]), marker);
23586  }
23587  }
23588  } // if (bondflag)
23589  } // if (marker != 0)
23590  } // i
23591  } // if (in->trifacelist)
23592 
23593  // Indentify subfaces from the mesh.
23594  // Create subfaces for hull faces (if they're not subface yet) and
23595  // interior faces which separate two different materials.
23596  eextras = in->numberoftetrahedronattributes;
23597  tetrahedrons->traversalinit();
23598  tetloop.tet = tetrahedrontraverse();
23599  while (tetloop.tet != (tetrahedron *) NULL) {
23600  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
23601  tspivot(tetloop, neighsh);
23602  if (neighsh.sh == NULL) {
23603  bondflag = 0;
23604  fsym(tetloop, checktet);
23605  if (ishulltet(checktet)) {
23606  // A hull face.
23607  if (!b->convex) {
23608  bondflag = 1; // Insert a hull subface.
23609  }
23610  } else {
23611  if (eextras > 0) {
23612  if (elemattribute(tetloop.tet, eextras - 1) !=
23613  elemattribute(checktet.tet, eextras - 1)) {
23614  bondflag = 1; // Insert an interior interface.
23615  }
23616  }
23617  }
23618  if (bondflag) {
23619  // Create a new subface.
23620  makeshellface(subfaces, &subloop);
23621  p[0] = org(tetloop);
23622  p[1] = dest(tetloop);
23623  p[2] = apex(tetloop);
23624  setshvertices(subloop, p[0], p[1], p[2]);
23625  // Create the point-to-subface map.
23626  sptr = sencode(subloop);
23627  for (j = 0; j < 3; j++) {
23628  setpointtype(p[j], FACETVERTEX); // initial type.
23629  setpoint2sh(p[j], sptr);
23630  }
23631  setshellmark(subloop, -1); // Default marker.
23632  // Insert the subface into the mesh.
23633  tsbond(tetloop, subloop);
23634  sesymself(subloop);
23635  tsbond(checktet, subloop);
23636  } // if (bondflag)
23637  } // if (neighsh.sh == NULL)
23638  }
23639  tetloop.tet = tetrahedrontraverse();
23640  }
23641 
23642  // Connect subfaces together.
23643  subfaces->traversalinit();
23644  subloop.shver = 0;
23645  subloop.sh = shellfacetraverse(subfaces);
23646  while (subloop.sh != (shellface *) NULL) {
23647  for (i = 0; i < 3; i++) {
23648  spivot(subloop, neighsh);
23649  if (neighsh.sh == NULL) {
23650  // Form a subface ring by linking all subfaces at this edge.
23651  // Traversing all faces of the tets at this edge.
23652  stpivot(subloop, tetloop);
23653  q[2] = apex(tetloop);
23654  neighsh = subloop;
23655  while (1) {
23656  fnextself(tetloop);
23657  tspivot(tetloop, nextsh);
23658  if (nextsh.sh != NULL) {
23659  // Do not connect itself.
23660  if (nextsh.sh != neighsh.sh) {
23661  // Link neighsh <= nextsh.
23662  sbond1(neighsh, nextsh);
23663  neighsh = nextsh;
23664  }
23665  }
23666  if (apex(tetloop) == q[2]) {
23667  break;
23668  }
23669  } // while (1)
23670  } // if (neighsh.sh == NULL)
23671  senextself(subloop);
23672  }
23673  subloop.sh = shellfacetraverse(subfaces);
23674  }
23675 
23676 
23677  // Segments will be introduced.
23678  if (in->edgelist != NULL) {
23679  // A .edge file is given. It may contain boundary edges. Insert them.
23680  for (i = 0; i < in->numberofedges; i++) {
23681  // Is it a segment?
23682  if (in->edgemarkerlist != NULL) {
23683  marker = in->edgemarkerlist[i];
23684  } else {
23685  // Edge markers are not available. Assume all of them are segments.
23686  marker = -1; // Default marker.
23687  }
23688  if (marker != 0) {
23689  // Insert a segment.
23690  idx = i * 2;
23691  for (j = 0; j < 2; j++) {
23692  p[j] = idx2verlist[in->edgelist[idx++]];
23693  }
23694  // Make sure all vertices are in the mesh. Avoid crash.
23695  for (j = 0; j < 2; j++) {
23696  decode(point2tet(p[j]), checktet);
23697  if (checktet.tet == NULL) break;
23698  }
23699  // Search the segment.
23700  bondflag = 0;
23701  if (j == 2) {
23702  if (getedge(p[0], p[1], &checktet)) {
23703  bondflag = 1;
23704  } else {
23705  if (b->verbose > 1) {
23706  printf("Warning: Searching segment #%d [%d,%d] mark=%d.\n",
23707  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]), marker);
23708  }
23709  // Search it globally.
23710  if (search_edge(p[0], p[1], checktet)) {
23711  bondflag = 1;
23712  }
23713  }
23714  }
23715  if (bondflag > 0) {
23716  // Create a new segment.
23717  makeshellface(subsegs, &segloop);
23718  setshvertices(segloop, p[0], p[1], NULL);
23719  // Create the point-to-segment map.
23720  sptr = sencode(segloop);
23721  for (j = 0; j < 2; j++) {
23722  setpointtype(p[j], RIDGEVERTEX); // initial type.
23723  setpoint2sh(p[j], sptr);
23724  }
23725  setshellmark(segloop, marker);
23726  // Insert the segment into the mesh.
23727  tetloop = checktet;
23728  q[2] = apex(checktet);
23729  subloop.sh = NULL;
23730  while (1) {
23731  tssbond1(tetloop, segloop);
23732  tspivot(tetloop, subloop);
23733  if (subloop.sh != NULL) {
23734  ssbond1(subloop, segloop);
23735  sbond1(segloop, subloop);
23736  }
23737  fnextself(tetloop);
23738  if (apex(tetloop) == q[2]) break;
23739  } // while (1)
23740  // Remember an adjacent tet for this segment.
23741  sstbond1(segloop, tetloop);
23742  } else {
23743  if (!b->quiet) {
23744  printf("Warning: Segment #%d [%d,%d] is missing.\n",
23745  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
23746  }
23747  }
23748  } // if (marker != 0)
23749  } // i
23750  } // if (in->edgelist)
23751 
23752  // Identify segments from the mesh.
23753  // Create segments for non-manifold edges (which are shared by more
23754  // than two subfaces), and for non-coplanar edges, i.e., two subfaces
23755  // form an dihedral angle > 'b->facet_separate_ang_tol' (degree).
23756  cosang_tol = cos(b->facet_separate_ang_tol / 180.0 * PI);
23757  subfaces->traversalinit();
23758  subloop.shver = 0;
23759  subloop.sh = shellfacetraverse(subfaces);
23760  while (subloop.sh != (shellface *) NULL) {
23761  for (i = 0; i < 3; i++) {
23762  sspivot(subloop, segloop);
23763  if (segloop.sh == NULL) {
23764  // Check if this edge is a segment.
23765  bondflag = 0;
23766  // Counter the number of subfaces at this edge.
23767  idx = 0;
23768  nextsh = subloop;
23769  while (1) {
23770  idx++;
23771  spivotself(nextsh);
23772  if (nextsh.sh == subloop.sh) break;
23773  }
23774  if (idx != 2) {
23775  // It's a non-manifold edge. Insert a segment.
23776  p[0] = sorg(subloop);
23777  p[1] = sdest(subloop);
23778  bondflag = 1;
23779  } else {
23780  spivot(subloop, neighsh);
23781  if (shellmark(subloop) != shellmark(neighsh)) {
23782  // It's an interior interface. Insert a segment.
23783  p[0] = sorg(subloop);
23784  p[1] = sdest(subloop);
23785  bondflag = 1;
23786  } else {
23787  if (!b->convex) {
23788  // Check the dihedral angle formed by the two subfaces.
23789  p[0] = sorg(subloop);
23790  p[1] = sdest(subloop);
23791  p[2] = sapex(subloop);
23792  p[3] = sapex(neighsh);
23793  facenormal(p[0], p[1], p[2], n1, 1, NULL);
23794  facenormal(p[0], p[1], p[3], n2, 1, NULL);
23795  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
23796  // Rounding.
23797  if (cosang > 1.0) cosang = 1.0;
23798  else if (cosang < -1.0) cosang = -1.0;
23799  if (cosang > cosang_tol) {
23800  bondflag = 1;
23801  }
23802  }
23803  }
23804  }
23805  if (bondflag) {
23806  // Create a new segment.
23807  makeshellface(subsegs, &segloop);
23808  setshvertices(segloop, p[0], p[1], NULL);
23809  // Create the point-to-segment map.
23810  sptr = sencode(segloop);
23811  for (j = 0; j < 2; j++) {
23812  setpointtype(p[j], RIDGEVERTEX); // initial type.
23813  setpoint2sh(p[j], sptr);
23814  }
23815  setshellmark(segloop, -1); // Default marker.
23816  // Insert the subface into the mesh.
23817  stpivot(subloop, tetloop);
23818  q[2] = apex(tetloop);
23819  while (1) {
23820  tssbond1(tetloop, segloop);
23821  tspivot(tetloop, neighsh);
23822  if (neighsh.sh != NULL) {
23823  ssbond1(neighsh, segloop);
23824  }
23825  fnextself(tetloop);
23826  if (apex(tetloop) == q[2]) break;
23827  } // while (1)
23828  // Remember an adjacent tet for this segment.
23829  sstbond1(segloop, tetloop);
23830  sbond1(segloop, subloop);
23831  } // if (bondflag)
23832  } // if (neighsh.sh == NULL)
23833  senextself(subloop);
23834  } // i
23835  subloop.sh = shellfacetraverse(subfaces);
23836  }
23837 
23838  // Remember the number of input segments.
23839  insegments = subsegs->items;
23840 
23841  if (!b->nobisect || checkconstraints) {
23842  // Mark Steiner points on segments and facets.
23843  // - all vertices which remaining type FEACTVERTEX become
23844  // Steiner points in facets (= FREEFACERVERTEX).
23845  // - vertices on segment need to be checked.
23846  face* segperverlist;
23847  int* idx2seglist;
23848  face parentseg, nextseg;
23849  verttype vt;
23850  REAL area, len, l1, l2;
23851  int fmarker;
23852 
23853  makepoint2submap(subsegs, idx2seglist, segperverlist);
23854 
23855  points->traversalinit();
23856  point ptloop = pointtraverse();
23857  while (ptloop != NULL) {
23858  vt = pointtype(ptloop);
23859  if (vt == VOLVERTEX) {
23860  setpointtype(ptloop, FREEVOLVERTEX);
23861  st_volref_count++;
23862  } else if (vt == FACETVERTEX) {
23863  setpointtype(ptloop, FREEFACETVERTEX);
23864  st_facref_count++;
23865  } else if (vt == RIDGEVERTEX) {
23866  idx = pointmark(ptloop) - in->firstnumber;
23867  if ((idx2seglist[idx + 1] - idx2seglist[idx]) == 2) {
23868  i = idx2seglist[idx];
23869  parentseg = segperverlist[i];
23870  nextseg = segperverlist[i + 1];
23871  sesymself(nextseg);
23872  p[0] = sorg(nextseg);
23873  p[1] = sdest(parentseg);
23874  // Check if three points p[0], ptloop, p[2] are (nearly) collinear.
23875  len = distance(p[0], p[1]);
23876  l1 = distance(p[0], ptloop);
23877  l2 = distance(ptloop, p[1]);
23878  if (((l1 + l2 - len) / len) < b->epsilon) {
23879  // They are (nearly) collinear.
23880  setpointtype(ptloop, FREESEGVERTEX);
23881  // Connect nextseg and parentseg together at ptloop.
23882  senextself(nextseg);
23883  senext2self(parentseg);
23884  sbond(nextseg, parentseg);
23885  st_segref_count++;
23886  }
23887  }
23888  }
23889  ptloop = pointtraverse();
23890  }
23891 
23892  // Are there area constraints?
23893  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
23894  // Set maximum area constraints on facets.
23895  for (i = 0; i < in->numberoffacetconstraints; i++) {
23896  fmarker = (int) in->facetconstraintlist[i * 2];
23897  area = in->facetconstraintlist[i * 2 + 1];
23898  subfaces->traversalinit();
23899  subloop.sh = shellfacetraverse(subfaces);
23900  while (subloop.sh != NULL) {
23901  if (shellmark(subloop) == fmarker) {
23902  setareabound(subloop, area);
23903  }
23904  subloop.sh = shellfacetraverse(subfaces);
23905  }
23906  }
23907  }
23908 
23909  // Are there length constraints?
23910  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
23911  // Set maximum length constraints on segments.
23912  int e1, e2;
23913  for (i = 0; i < in->numberofsegmentconstraints; i++) {
23914  e1 = (int) in->segmentconstraintlist[i * 3];
23915  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
23916  len = in->segmentconstraintlist[i * 3 + 2];
23917  // Search for edge [e1, e2].
23918  idx = e1 - in->firstnumber;
23919  for (j = idx2seglist[idx]; j < idx2seglist[idx + 1]; j++) {
23920  parentseg = segperverlist[j];
23921  if (pointmark(sdest(parentseg)) == e2) {
23922  setareabound(parentseg, len);
23923  break;
23924  }
23925  }
23926  }
23927  }
23928 
23929  delete [] idx2seglist;
23930  delete [] segperverlist;
23931  }
23932 
23933 
23934  // Set global flags.
23935  checksubsegflag = 1;
23936  checksubfaceflag = 1;
23937 
23938  delete [] idx2verlist;
23939  delete [] ver2tetarray;
23940 }
23941 
23943 // //
23944 // scoutpoint() Search a point in mesh. //
23945 // //
23946 // This function searches the point in a mesh whose domain may be not convex.//
23947 // In case of a convex domain, the locate() function is sufficient. //
23948 // //
23949 // If 'randflag' is used, randomly select a start searching tet. Otherwise, //
23950 // start searching directly from 'searchtet'. //
23951 // //
23953 
23954 int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
23955 {
23956  point pa, pb, pc, pd;
23957  enum locateresult loc = OUTSIDE;
23958  REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
23959  int t1ver;
23960 
23961 
23962  // Randomly select a good starting tet.
23963  if (randflag) {
23964  randomsample(searchpt, searchtet);
23965  } else {
23966  if (searchtet->tet == NULL) {
23967  *searchtet = recenttet;
23968  }
23969  }
23970  loc = locate(searchpt, searchtet);
23971 
23972  if (loc == OUTSIDE) {
23973  if (b->convex) { // -c option
23974  // The point lies outside of the convex hull.
23975  return (int) loc;
23976  }
23977  // Test if it lies nearly on the hull face.
23978  // Reuse vol, ori1.
23979  pa = org(*searchtet);
23980  pb = dest(*searchtet);
23981  pc = apex(*searchtet);
23982  vol = triarea(pa, pb, pc);
23983  ori1 = orient3dfast(pa, pb, pc, searchpt);
23984  if (fabs(ori1 / vol) < b->epsilon) {
23985  loc = ONFACE; // On face (or on edge, or on vertex).
23986  fsymself(*searchtet);
23987  }
23988  }
23989 
23990  if (loc != OUTSIDE) {
23991  // Round the result of location.
23992  pa = org(*searchtet);
23993  pb = dest(*searchtet);
23994  pc = apex(*searchtet);
23995  pd = oppo(*searchtet);
23996  vol = orient3dfast(pa, pb, pc, pd);
23997  ori1 = orient3dfast(pa, pb, pc, searchpt);
23998  ori2 = orient3dfast(pb, pa, pd, searchpt);
23999  ori3 = orient3dfast(pc, pb, pd, searchpt);
24000  ori4 = orient3dfast(pa, pc, pd, searchpt);
24001  if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
24002  if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
24003  if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
24004  if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
24005  } else { // if (loc == OUTSIDE) {
24006  // Do a brute force search for the point (with rounding).
24007  tetrahedrons->traversalinit();
24008  searchtet->tet = tetrahedrontraverse();
24009  while (searchtet->tet != NULL) {
24010  pa = org(*searchtet);
24011  pb = dest(*searchtet);
24012  pc = apex(*searchtet);
24013  pd = oppo(*searchtet);
24014 
24015  vol = orient3dfast(pa, pb, pc, pd);
24016  if (vol < 0) {
24017  ori1 = orient3dfast(pa, pb, pc, searchpt);
24018  if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
24019  if (ori1 <= 0) {
24020  ori2 = orient3dfast(pb, pa, pd, searchpt);
24021  if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
24022  if (ori2 <= 0) {
24023  ori3 = orient3dfast(pc, pb, pd, searchpt);
24024  if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
24025  if (ori3 <= 0) {
24026  ori4 = orient3dfast(pa, pc, pd, searchpt);
24027  if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
24028  if (ori4 <= 0) {
24029  // Found the tet. Return its location.
24030  break;
24031  } // ori4
24032  } // ori3
24033  } // ori2
24034  } // ori1
24035  }
24036 
24037  searchtet->tet = tetrahedrontraverse();
24038  } // while (searchtet->tet != NULL)
24039  nonregularcount++; // Re-use this counter.
24040  }
24041 
24042  if (searchtet->tet != NULL) {
24043  // Return the point location.
24044  if (ori1 == 0) { // on face [a,b,c]
24045  if (ori2 == 0) { // on edge [a,b].
24046  if (ori3 == 0) { // on vertex [b].
24047  enextself(*searchtet); // [b,c,a,d]
24048  loc = ONVERTEX;
24049  } else {
24050  if (ori4 == 0) { // on vertex [a]
24051  loc = ONVERTEX; // [a,b,c,d]
24052  } else {
24053  loc = ONEDGE; // [a,b,c,d]
24054  }
24055  }
24056  } else { // ori2 != 0
24057  if (ori3 == 0) { // on edge [b,c]
24058  if (ori4 == 0) { // on vertex [c]
24059  eprevself(*searchtet); // [c,a,b,d]
24060  loc = ONVERTEX;
24061  } else {
24062  enextself(*searchtet); // [b,c,a,d]
24063  loc = ONEDGE;
24064  }
24065  } else { // ori3 != 0
24066  if (ori4 == 0) { // on edge [c,a]
24067  eprevself(*searchtet); // [c,a,b,d]
24068  loc = ONEDGE;
24069  } else {
24070  loc = ONFACE;
24071  }
24072  }
24073  }
24074  } else { // ori1 != 0
24075  if (ori2 == 0) { // on face [b,a,d]
24076  esymself(*searchtet); // [b,a,d,c]
24077  if (ori3 == 0) { // on edge [b,d]
24078  eprevself(*searchtet); // [d,b,a,c]
24079  if (ori4 == 0) { // on vertex [d]
24080  loc = ONVERTEX;
24081  } else {
24082  loc = ONEDGE;
24083  }
24084  } else { // ori3 != 0
24085  if (ori4 == 0) { // on edge [a,d]
24086  enextself(*searchtet); // [a,d,b,c]
24087  loc = ONEDGE;
24088  } else {
24089  loc = ONFACE;
24090  }
24091  }
24092  } else { // ori2 != 0
24093  if (ori3 == 0) { // on face [c,b,d]
24094  enextself(*searchtet);
24095  esymself(*searchtet);
24096  if (ori4 == 0) { // on edge [c,d]
24097  eprevself(*searchtet);
24098  loc = ONEDGE;
24099  } else {
24100  loc = ONFACE;
24101  }
24102  } else {
24103  if (ori4 == 0) { // on face [a,c,d]
24104  eprevself(*searchtet);
24105  esymself(*searchtet);
24106  loc = ONFACE;
24107  } else { // inside tet [a,b,c,d]
24108  loc = INTETRAHEDRON;
24109  } // ori4
24110  } // ori3
24111  } // ori2
24112  } // ori1
24113  } else {
24114  loc = OUTSIDE;
24115  }
24116 
24117  return (int) loc;
24118 }
24119 
24121 // //
24122 // getpointmeshsize() Interpolate the mesh size at given point. //
24123 // //
24124 // 'iloc' indicates the location of the point w.r.t. 'searchtet'. The size //
24125 // is obtained by linear interpolation on the vertices of the tet. //
24126 // //
24128 
24129 REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
24130 {
24131  point *pts, pa, pb, pc;
24132  REAL volume, vol[4], wei[4];
24133  REAL size;
24134  int i;
24135 
24136  size = 0;
24137 
24138  if (iloc == (int) INTETRAHEDRON) {
24139  pts = (point *) &(searchtet->tet[4]);
24140  // Only do interpolation if all vertices have non-zero sizes.
24141  if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
24142  (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) {
24143  // P1 interpolation.
24144  volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
24145  vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
24146  vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
24147  vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
24148  vol[3] = orient3dfast(pts[0], pts[1], pts[2], searchpt);
24149  for (i = 0; i < 4; i++) {
24150  wei[i] = fabs(vol[i] / volume);
24151  size += (wei[i] * pts[i][pointmtrindex]);
24152  }
24153  }
24154  } else if (iloc == (int) ONFACE) {
24155  pa = org(*searchtet);
24156  pb = dest(*searchtet);
24157  pc = apex(*searchtet);
24158  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
24159  (pc[pointmtrindex] > 0)) {
24160  volume = triarea(pa, pb, pc);
24161  vol[0] = triarea(searchpt, pb, pc);
24162  vol[1] = triarea(pa, searchpt, pc);
24163  vol[2] = triarea(pa, pb, searchpt);
24164  size = (vol[0] / volume) * pa[pointmtrindex]
24165  + (vol[1] / volume) * pb[pointmtrindex]
24166  + (vol[2] / volume) * pc[pointmtrindex];
24167  }
24168  } else if (iloc == (int) ONEDGE) {
24169  pa = org(*searchtet);
24170  pb = dest(*searchtet);
24171  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
24172  volume = distance(pa, pb);
24173  vol[0] = distance(searchpt, pb);
24174  vol[1] = distance(pa, searchpt);
24175  size = (vol[0] / volume) * pa[pointmtrindex]
24176  + (vol[1] / volume) * pb[pointmtrindex];
24177  }
24178  } else if (iloc == (int) ONVERTEX) {
24179  pa = org(*searchtet);
24180  if (pa[pointmtrindex] > 0) {
24181  size = pa[pointmtrindex];
24182  }
24183  }
24184 
24185  return size;
24186 }
24187 
24189 // //
24190 // interpolatemeshsize() Interpolate the mesh size from a background mesh //
24191 // (source) to the current mesh (destination). //
24192 // //
24194 
24195 void tetgenmesh::interpolatemeshsize()
24196 {
24197  triface searchtet;
24198  point ploop;
24199  REAL minval = 0.0, maxval = 0.0;
24200  int iloc;
24201  int count;
24202 
24203  if (!b->quiet) {
24204  printf("Interpolating mesh size ...\n");
24205  }
24206 
24207  long bak_nonregularcount = nonregularcount;
24208  nonregularcount = 0l; // Count the number of (slow) global searches.
24209  long baksmaples = bgm->samples;
24210  bgm->samples = 3l;
24211  count = 0; // Count the number of interpolated points.
24212 
24213  // Interpolate sizes for all points in the current mesh.
24214  points->traversalinit();
24215  ploop = pointtraverse();
24216  while (ploop != NULL) {
24217  // Search a tet in bgm which containing this point.
24218  searchtet.tet = NULL;
24219  iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
24220  if (iloc != (int) OUTSIDE) {
24221  // Interpolate the mesh size.
24222  ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
24223  setpoint2bgmtet(ploop, bgm->encode(searchtet));
24224  if (count == 0) {
24225  // This is the first interpolated point.
24226  minval = maxval = ploop[pointmtrindex];
24227  } else {
24228  if (ploop[pointmtrindex] < minval) {
24229  minval = ploop[pointmtrindex];
24230  }
24231  if (ploop[pointmtrindex] > maxval) {
24232  maxval = ploop[pointmtrindex];
24233  }
24234  }
24235  count++;
24236  } else {
24237  if (!b->quiet) {
24238  printf("Warnning: Failed to locate point %d in source mesh.\n",
24239  pointmark(ploop));
24240  }
24241  }
24242  ploop = pointtraverse();
24243  }
24244 
24245  if (b->verbose) {
24246  printf(" Interoplated %d points.\n", count);
24247  if (nonregularcount > 0l) {
24248  printf(" Performed %ld brute-force searches.\n", nonregularcount);
24249  }
24250  printf(" Size rangle [%.17g, %.17g].\n", minval, maxval);
24251  }
24252 
24253  bgm->samples = baksmaples;
24254  nonregularcount = bak_nonregularcount;
24255 }
24256 
24258 // //
24259 // insertconstrainedpoints() Insert a list of points into the mesh. //
24260 // //
24261 // Assumption: The bounding box of the insert point set should be no larger //
24262 // than the bounding box of the mesh. (Required by point sorting). //
24263 // //
24265 
24266 void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen,
24267  int rejflag)
24268 {
24269  triface searchtet, spintet;
24270  face splitsh;
24271  face splitseg;
24272  insertvertexflags ivf;
24273  flipconstraints fc;
24274  int randflag = 0;
24275  int t1ver;
24276  int i;
24277 
24278  if (b->verbose) {
24279  printf(" Inserting %d constrained points\n", arylen);
24280  }
24281 
24282  if (b->no_sort) { // -b/1 option.
24283  if (b->verbose) {
24284  printf(" Using the input order.\n");
24285  }
24286  } else {
24287  if (b->verbose) {
24288  printf(" Permuting vertices.\n");
24289  }
24290  point swappoint;
24291  int randindex;
24292  srand(arylen);
24293  for (i = 0; i < arylen; i++) {
24294  randindex = rand() % (i + 1);
24295  swappoint = insertarray[i];
24296  insertarray[i] = insertarray[randindex];
24297  insertarray[randindex] = swappoint;
24298  }
24299  if (b->brio_hilbert) { // -b1 option
24300  if (b->verbose) {
24301  printf(" Sorting vertices.\n");
24302  }
24303  hilbert_init(in->mesh_dim);
24304  int ngroup = 0;
24305  brio_multiscale_sort(insertarray, arylen, b->brio_threshold,
24306  b->brio_ratio, &ngroup);
24307  } else { // -b0 option.
24308  randflag = 1;
24309  } // if (!b->brio_hilbert)
24310  } // if (!b->no_sort)
24311 
24312  long bak_nonregularcount = nonregularcount;
24313  nonregularcount = 0l;
24314  long baksmaples = samples;
24315  samples = 3l; // Use at least 3 samples. Updated in randomsample().
24316 
24317  long bak_seg_count = st_segref_count;
24318  long bak_fac_count = st_facref_count;
24319  long bak_vol_count = st_volref_count;
24320 
24321  // Initialize the insertion parameters.
24322  if (b->incrflip) { // -l option
24323  // Use incremental flip algorithm.
24324  ivf.bowywat = 0;
24325  ivf.lawson = 1;
24326  ivf.validflag = 0; // No need to validate the cavity.
24327  fc.enqflag = 2;
24328  } else {
24329  // Use Bowyer-Watson algorithm.
24330  ivf.bowywat = 1;
24331  ivf.lawson = 0;
24332  ivf.validflag = 1; // Validate the B-W cavity.
24333  }
24334  ivf.rejflag = rejflag;
24335  ivf.chkencflag = 0;
24336  ivf.sloc = (int) INSTAR;
24337  ivf.sbowywat = 3;
24338  ivf.splitbdflag = 1;
24339  ivf.respectbdflag = 1;
24340  ivf.assignmeshsize = b->metric;
24341 
24342  encseglist = new arraypool(sizeof(face), 8);
24343  encshlist = new arraypool(sizeof(badface), 8);
24344 
24345  // Insert the points.
24346  for (i = 0; i < arylen; i++) {
24347  // Find the location of the inserted point.
24348  // Do not use 'recenttet', since the mesh may be non-convex.
24349  searchtet.tet = NULL;
24350  ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
24351 
24352  // Decide the right type for this point.
24353  setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
24354  splitsh.sh = NULL;
24355  splitseg.sh = NULL;
24356  if (ivf.iloc == (int) ONEDGE) {
24357  if (issubseg(searchtet)) {
24358  tsspivot1(searchtet, splitseg);
24359  setpointtype(insertarray[i], FREESEGVERTEX);
24360  //ivf.rejflag = 0;
24361  } else {
24362  // Check if it is a subface edge.
24363  spintet = searchtet;
24364  while (1) {
24365  if (issubface(spintet)) {
24366  tspivot(spintet, splitsh);
24367  setpointtype(insertarray[i], FREEFACETVERTEX);
24368  //ivf.rejflag |= 1;
24369  break;
24370  }
24371  fnextself(spintet);
24372  if (spintet.tet == searchtet.tet) break;
24373  }
24374  }
24375  } else if (ivf.iloc == (int) ONFACE) {
24376  if (issubface(searchtet)) {
24377  tspivot(searchtet, splitsh);
24378  setpointtype(insertarray[i], FREEFACETVERTEX);
24379  //ivf.rejflag |= 1;
24380  }
24381  }
24382 
24383  // Now insert the point.
24384  if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
24385  if (flipstack != NULL) {
24386  // There are queued faces. Use flips to recover Delaunayness.
24387  lawsonflip3d(&fc);
24388  // There may be unflippable edges. Ignore them.
24389  unflipqueue->restart();
24390  }
24391  // Update the Steiner counters.
24392  if (pointtype(insertarray[i]) == FREESEGVERTEX) {
24393  st_segref_count++;
24394  } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
24395  st_facref_count++;
24396  } else {
24397  st_volref_count++;
24398  }
24399  } else {
24400  // Point is not inserted.
24401  //pointdealloc(insertarray[i]);
24402  setpointtype(insertarray[i], UNUSEDVERTEX);
24403  unuverts++;
24404  encseglist->restart();
24405  encshlist->restart();
24406  }
24407  } // i
24408 
24409  delete encseglist;
24410  delete encshlist;
24411 
24412  if (b->verbose) {
24413  printf(" Inserted %ld (%ld, %ld, %ld) vertices.\n",
24414  st_segref_count + st_facref_count + st_volref_count -
24415  (bak_seg_count + bak_fac_count + bak_vol_count),
24416  st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
24417  st_volref_count - bak_vol_count);
24418  if (nonregularcount > 0l) {
24419  printf(" Performed %ld brute-force searches.\n", nonregularcount);
24420  }
24421  }
24422 
24423  nonregularcount = bak_nonregularcount;
24424  samples = baksmaples;
24425 }
24426 
24427 void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
24428 {
24429  point *insertarray, newpt;
24430  REAL x, y, z, w;
24431  int index, attribindex, mtrindex;
24432  int arylen, i, j;
24433 
24434  if (!b->quiet) {
24435  printf("Inserting constrained points ...\n");
24436  }
24437 
24438  insertarray = new point[addio->numberofpoints];
24439  arylen = 0;
24440  index = 0;
24441  attribindex = 0;
24442  mtrindex = 0;
24443 
24444  for (i = 0; i < addio->numberofpoints; i++) {
24445  x = addio->pointlist[index++];
24446  y = addio->pointlist[index++];
24447  z = addio->pointlist[index++];
24448  // Test if this point lies inside the bounding box.
24449  if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
24450  (z < zmin) || (z > zmax)) {
24451  if (b->verbose) {
24452  printf("Warning: Point #%d lies outside the bounding box. Ignored\n",
24453  i + in->firstnumber);
24454  }
24455  continue;
24456  }
24457  makepoint(&newpt, UNUSEDVERTEX);
24458  newpt[0] = x;
24459  newpt[1] = y;
24460  newpt[2] = z;
24461  // Read the point attributes. (Including point weights.)
24462  for (j = 0; j < addio->numberofpointattributes; j++) {
24463  newpt[3 + j] = addio->pointattributelist[attribindex++];
24464  }
24465  // Read the point metric tensor.
24466  for (j = 0; j < addio->numberofpointmtrs; j++) {
24467  newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
24468  }
24469  if (b->weighted) { // -w option
24470  if (addio->numberofpointattributes > 0) {
24471  // The first point attribute is its weight.
24472  w = newpt[3];
24473  } else {
24474  // No given weight available. Default choose the maximum
24475  // absolute value among its coordinates.
24476  w = fabs(x);
24477  if (w < fabs(y)) w = fabs(y);
24478  if (w < fabs(z)) w = fabs(z);
24479  }
24480  if (b->weighted_param == 0) {
24481  newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
24482  } else { // -w1 option
24483  newpt[3] = w; // Regular tetrahedralization.
24484  }
24485  }
24486  insertarray[arylen] = newpt;
24487  arylen++;
24488  } // i
24489 
24490  // Insert the points.
24491  int rejflag = 0; // Do not check encroachment.
24492  if (b->metric) { // -m option.
24493  rejflag |= 4; // Reject it if it lies in some protecting balls.
24494  }
24495 
24496  insertconstrainedpoints(insertarray, arylen, rejflag);
24497 
24498  delete [] insertarray;
24499 }
24500 
24502 // //
24503 // meshcoarsening() Deleting (selected) vertices. //
24504 // //
24506 
24507 void tetgenmesh::collectremovepoints(arraypool *remptlist)
24508 {
24509  point ptloop, *parypt;
24510  verttype vt;
24511 
24512  // If a mesh sizing function is given. Collect vertices whose mesh size
24513  // is greater than its smallest edge length.
24514  if (b->metric) { // -m option
24515  REAL len, smlen;
24516  int i;
24517  points->traversalinit();
24518  ptloop = pointtraverse();
24519  while (ptloop != NULL) {
24520  // Do not remove a boundary vertex
24521  vt = pointtype(ptloop);
24522  if ((vt == RIDGEVERTEX) || (vt == ACUTEVERTEX) || (vt == FACETVERTEX) ||
24523  (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX) || (vt == UNUSEDVERTEX)) {
24524  ptloop = pointtraverse();
24525  continue;
24526  }
24527  if (ptloop[pointmtrindex] > 0) {
24528  // Get the smallest edge length at this vertex.
24529  getvertexstar(1, ptloop, cavetetlist, cavetetvertlist, NULL);
24530  parypt = (point *) fastlookup(cavetetvertlist, 0);
24531  smlen = distance(ptloop, *parypt);
24532  for (i = 1; i < cavetetvertlist->objects; i++) {
24533  parypt = (point *) fastlookup(cavetetvertlist, i);
24534  len = distance(ptloop, *parypt);
24535  if (len < smlen) {
24536  smlen = len;
24537  }
24538  }
24539  cavetetvertlist->restart();
24540  cavetetlist->restart();
24541  if (smlen < ptloop[pointmtrindex]) {
24542  pinfect(ptloop);
24543  remptlist->newindex((void **) &parypt);
24544  *parypt = ptloop;
24545  }
24546  }
24547  ptloop = pointtraverse();
24548  }
24549  if (b->verbose > 1) {
24550  printf(" Coarsen %ld oversized points.\n", remptlist->objects);
24551  }
24552  }
24553 
24554  // If 'in->pointmarkerlist' exists, Collect vertices with markers '-1'.
24555  if (in->pointmarkerlist != NULL) {
24556  long bak_count = remptlist->objects;
24557  points->traversalinit();
24558  ptloop = pointtraverse();
24559  int index = 0;
24560  while (ptloop != NULL) {
24561  if (index < in->numberofpoints) {
24562  if (in->pointmarkerlist[index] == -1) {
24563  pinfect(ptloop);
24564  remptlist->newindex((void **) &parypt);
24565  *parypt = ptloop;
24566  }
24567  } else {
24568  // Remaining are not input points. Stop here.
24569  break;
24570  }
24571  index++;
24572  ptloop = pointtraverse();
24573  }
24574  if (b->verbose > 1) {
24575  printf(" Coarsen %ld marked points.\n", remptlist->objects - bak_count);
24576  }
24577  } // if (in->pointmarkerlist != NULL)
24578 
24579  if (b->coarsen_param > 0) { // -R1/#
24580  // Remove a coarsen_percent number of interior points.
24581  if (b->verbose > 1) {
24582  printf(" Coarsen %g percent of interior points.\n",
24583  b->coarsen_percent * 100.0);
24584  }
24585  arraypool *intptlist = new arraypool(sizeof(point *), 10);
24586  // Count the total number of interior points.
24587  points->traversalinit();
24588  ptloop = pointtraverse();
24589  while (ptloop != NULL) {
24590  vt = pointtype(ptloop);
24591  if ((vt == VOLVERTEX) || (vt == FREEVOLVERTEX) ||
24592  (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX)) {
24593  intptlist->newindex((void **) &parypt);
24594  *parypt = ptloop;
24595  }
24596  ptloop = pointtraverse();
24597  }
24598  if (intptlist->objects > 0l) {
24599  // Sort the list of points randomly.
24600  point *parypt_i, swappt;
24601  int randindex, i;
24602  srand(intptlist->objects);
24603  for (i = 0; i < intptlist->objects; i++) {
24604  randindex = rand() % (i + 1); // randomnation(i + 1);
24605  parypt_i = (point *) fastlookup(intptlist, i);
24606  parypt = (point *) fastlookup(intptlist, randindex);
24607  // Swap this two points.
24608  swappt = *parypt_i;
24609  *parypt_i = *parypt;
24610  *parypt = swappt;
24611  }
24612  int remcount = (int) ((REAL) intptlist->objects * b->coarsen_percent);
24613  // Return the first remcount points.
24614  for (i = 0; i < remcount; i++) {
24615  parypt_i = (point *) fastlookup(intptlist, i);
24616  if (!pinfected(*parypt_i)) {
24617  pinfected(*parypt_i);
24618  remptlist->newindex((void **) &parypt);
24619  *parypt = *parypt_i;
24620  }
24621  }
24622  }
24623  delete intptlist;
24624  }
24625 
24626  // Unmark all collected vertices.
24627  for (int i = 0; i < remptlist->objects; i++) {
24628  parypt = (point *) fastlookup(remptlist, i);
24629  puninfect(*parypt);
24630  }
24631 }
24632 
24633 void tetgenmesh::meshcoarsening()
24634 {
24635  arraypool *remptlist;
24636 
24637  if (!b->quiet) {
24638  printf("Mesh coarsening ...\n");
24639  }
24640 
24641  // Collect the set of points to be removed
24642  remptlist = new arraypool(sizeof(point *), 10);
24643  collectremovepoints(remptlist);
24644 
24645  if (remptlist->objects == 0l) {
24646  delete remptlist;
24647  return;
24648  }
24649 
24650  if (b->verbose) {
24651  if (remptlist->objects > 0l) {
24652  printf(" Removing %ld points...\n", remptlist->objects);
24653  }
24654  }
24655 
24656  point *parypt, *plastpt;
24657  long ms = remptlist->objects;
24658  int nit = 0;
24659  int bak_fliplinklevel = b->fliplinklevel;
24660  b->fliplinklevel = -1;
24661  autofliplinklevel = 1; // Init value.
24662  int i;
24663 
24664  while (1) {
24665 
24666  if (b->verbose > 1) {
24667  printf(" Removing points [%s level = %2d] #: %ld.\n",
24668  (b->fliplinklevel > 0) ? "fixed" : "auto",
24669  (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
24670  remptlist->objects);
24671  }
24672 
24673  // Remove the list of points.
24674  for (i = 0; i < remptlist->objects; i++) {
24675  parypt = (point *) fastlookup(remptlist, i);
24676  if (removevertexbyflips(*parypt)) {
24677  // Move the last entry to the current place.
24678  plastpt = (point *) fastlookup(remptlist, remptlist->objects - 1);
24679  *parypt = *plastpt;
24680  remptlist->objects--;
24681  i--;
24682  }
24683  }
24684 
24685  if (remptlist->objects > 0l) {
24686  if (b->fliplinklevel >= 0) {
24687  break; // We have tried all levels.
24688  }
24689  if (remptlist->objects == ms) {
24690  nit++;
24691  if (nit >= 3) {
24692  // Do the last round with unbounded flip link level.
24693  b->fliplinklevel = 100000;
24694  }
24695  } else {
24696  ms = remptlist->objects;
24697  if (nit > 0) {
24698  nit--;
24699  }
24700  }
24701  autofliplinklevel+=b->fliplinklevelinc;
24702  } else {
24703  // All points are removed.
24704  break;
24705  }
24706  } // while (1)
24707 
24708  if (remptlist->objects > 0l) {
24709  if (b->verbose) {
24710  printf(" %ld points are not removed !\n", remptlist->objects);
24711  }
24712  }
24713 
24714  b->fliplinklevel = bak_fliplinklevel;
24715  delete remptlist;
24716 }
24717 
24721 
24725 
24727 // //
24728 // makefacetverticesmap() Create a map from facet to its vertices. //
24729 // //
24730 // All facets will be indexed (starting from 0). The map is saved in two //
24731 // global arrays: 'idx2facetlist' and 'facetverticeslist'. //
24732 // //
24734 
24735 void tetgenmesh::makefacetverticesmap()
24736 {
24737  arraypool *facetvertexlist, *vertlist, **paryvertlist;
24738  face subloop, neighsh, *parysh, *parysh1;
24739  point pa, *ppt, *parypt;
24740  verttype vt;
24741  int facetindex, totalvertices;
24742  int i, j, k;
24743 
24744  if (b->verbose) {
24745  printf(" Creating the facet vertices map.\n");
24746  }
24747 
24748  facetvertexlist = new arraypool(sizeof(arraypool *), 10);
24749  facetindex = totalvertices = 0;
24750 
24751  subfaces->traversalinit();
24752  subloop.sh = shellfacetraverse(subfaces);
24753  while (subloop.sh != NULL) {
24754  if (!sinfected(subloop)) {
24755  // A new facet. Create its vertices list.
24756  vertlist = new arraypool(sizeof(point *), 8);
24757  ppt = (point *) &(subloop.sh[3]);
24758  for (k = 0; k < 3; k++) {
24759  vt = pointtype(ppt[k]);
24760  if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
24761  pinfect(ppt[k]);
24762  vertlist->newindex((void **) &parypt);
24763  *parypt = ppt[k];
24764  }
24765  }
24766  sinfect(subloop);
24767  caveshlist->newindex((void **) &parysh);
24768  *parysh = subloop;
24769  for (i = 0; i < caveshlist->objects; i++) {
24770  parysh = (face *) fastlookup(caveshlist, i);
24771  setfacetindex(*parysh, facetindex);
24772  for (j = 0; j < 3; j++) {
24773  if (!isshsubseg(*parysh)) {
24774  spivot(*parysh, neighsh);
24775  if (!sinfected(neighsh)) {
24776  pa = sapex(neighsh);
24777  if (!pinfected(pa)) {
24778  vt = pointtype(pa);
24779  if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
24780  pinfect(pa);
24781  vertlist->newindex((void **) &parypt);
24782  *parypt = pa;
24783  }
24784  }
24785  sinfect(neighsh);
24786  caveshlist->newindex((void **) &parysh1);
24787  *parysh1 = neighsh;
24788  }
24789  }
24790  senextself(*parysh);
24791  }
24792  } // i
24793  totalvertices += (int) vertlist->objects;
24794  // Uninfect facet vertices.
24795  for (k = 0; k < vertlist->objects; k++) {
24796  parypt = (point *) fastlookup(vertlist, k);
24797  puninfect(*parypt);
24798  }
24799  caveshlist->restart();
24800  // Save this vertex list.
24801  facetvertexlist->newindex((void **) &paryvertlist);
24802  *paryvertlist = vertlist;
24803  facetindex++;
24804  }
24805  subloop.sh = shellfacetraverse(subfaces);
24806  }
24807 
24808  // All subfaces are infected. Uninfect them.
24809  subfaces->traversalinit();
24810  subloop.sh = shellfacetraverse(subfaces);
24811  while (subloop.sh != NULL) {
24812  suninfect(subloop);
24813  subloop.sh = shellfacetraverse(subfaces);
24814  }
24815 
24816  if (b->verbose) {
24817  printf(" Found %ld facets.\n", facetvertexlist->objects);
24818  }
24819 
24820  idx2facetlist = new int[facetindex + 1];
24821  facetverticeslist = new point[totalvertices];
24822 
24823  totalworkmemory += ((facetindex + 1) * sizeof(int) +
24824  totalvertices * sizeof(point *));
24825 
24826  idx2facetlist[0] = 0;
24827  for (i = 0, k = 0; i < facetindex; i++) {
24828  paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24829  vertlist = *paryvertlist;
24830  idx2facetlist[i + 1] = (idx2facetlist[i] + (int) vertlist->objects);
24831  for (j = 0; j < vertlist->objects; j++) {
24832  parypt = (point *) fastlookup(vertlist, j);
24833  facetverticeslist[k] = *parypt;
24834  k++;
24835  }
24836  }
24837 
24838  // Free the lists.
24839  for (i = 0; i < facetvertexlist->objects; i++) {
24840  paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24841  vertlist = *paryvertlist;
24842  delete vertlist;
24843  }
24844  delete facetvertexlist;
24845 }
24846 
24848 // //
24849 // Check whether two segments, or a segment and a facet, or two facets are //
24850 // adjacent to each other. //
24851 // //
24853 
24854 int tetgenmesh::segsegadjacent(face *seg1, face *seg2)
24855 {
24856  int segidx1 = getfacetindex(*seg1);
24857  int segidx2 = getfacetindex(*seg2);
24858 
24859  if (segidx1 == segidx2) return 0;
24860 
24861  point pa1 = segmentendpointslist[segidx1 * 2];
24862  point pb1 = segmentendpointslist[segidx1 * 2 + 1];
24863  point pa2 = segmentendpointslist[segidx2 * 2];
24864  point pb2 = segmentendpointslist[segidx2 * 2 + 1];
24865 
24866  if ((pa1 == pa2) || (pa1 == pb2) || (pb1 == pa2) || (pb1 == pb2)) {
24867  return 1;
24868  }
24869  return 0;
24870 }
24871 
24872 int tetgenmesh::segfacetadjacent(face *subseg, face *subsh)
24873 {
24874  int segidx = getfacetindex(*subseg);
24875  point pa = segmentendpointslist[segidx * 2];
24876  point pb = segmentendpointslist[segidx * 2 + 1];
24877 
24878  pinfect(pa);
24879  pinfect(pb);
24880 
24881  int fidx = getfacetindex(*subsh);
24882  int count = 0, i;
24883 
24884  for (i = idx2facetlist[fidx]; i < idx2facetlist[fidx+1]; i++) {
24885  if (pinfected(facetverticeslist[i])) count++;
24886  }
24887 
24888  puninfect(pa);
24889  puninfect(pb);
24890 
24891  return count == 1;
24892 }
24893 
24894 int tetgenmesh::facetfacetadjacent(face *subsh1, face *subsh2)
24895 {
24896  int count = 0, i;
24897 
24898  int fidx1 = getfacetindex(*subsh1);
24899  int fidx2 = getfacetindex(*subsh2);
24900 
24901  if (fidx1 == fidx2) return 0;
24902 
24903  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24904  pinfect(facetverticeslist[i]);
24905  }
24906 
24907  for (i = idx2facetlist[fidx2]; i < idx2facetlist[fidx2+1]; i++) {
24908  if (pinfected(facetverticeslist[i])) count++;
24909  }
24910 
24911  // Uninfect the vertices.
24912  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24913  puninfect(facetverticeslist[i]);
24914  }
24915 
24916  return count > 0;
24917 }
24918 
24920 // //
24921 // save_segmentpoint_insradius(), save_facetpoint_insradius() //
24922 // //
24923 // Determine and save the relaxed insertion radius of a Steiner point on a //
24924 // segment or a facet. By default, it is the closet distance to the parent //
24925 // point of this Steiner point. But may be larger than it. //
24926 // //
24928 
24929 void tetgenmesh::save_segmentpoint_insradius(point segpt,point parentpt,REAL r)
24930 {
24931  REAL rv = r, rp;
24932  if (pointtype(parentpt) == FREESEGVERTEX) {
24933  face parentseg1, parentseg2;
24934  sdecode(point2sh(segpt), parentseg1);
24935  sdecode(point2sh(parentpt), parentseg2);
24936  if (segsegadjacent(&parentseg1, &parentseg2)) {
24937  rp = getpointinsradius(parentpt);
24938  if (rv < rp) {
24939  // The relaxed insertion radius of 'newpt'.
24940  rv = rp;
24941  }
24942  }
24943  } else if (pointtype(parentpt) == FREEFACETVERTEX) {
24944  face parentseg, parentsh;
24945  sdecode(point2sh(segpt), parentseg);
24946  sdecode(point2sh(parentpt), parentsh);
24947  if (segfacetadjacent(&parentseg, &parentsh)) {
24948  rp = getpointinsradius(parentpt);
24949  if ((sqrt(2.0) * rv) < rp) { // if (rv < rp) {
24950  // The relaxed insertion radius of 'newpt'.
24951  rv = rp / sqrt(2.0); // rv = rp;
24952  }
24953  }
24954  }
24955  setpointinsradius(segpt, rv);
24956 }
24957 
24958 void tetgenmesh::save_facetpoint_insradius(point facpt,point parentpt,REAL r)
24959 {
24960  REAL rv = r, rp;
24961  if (pointtype(parentpt) == FREESEGVERTEX) {
24962  face parentseg, parentsh;
24963  sdecode(point2sh(parentpt), parentseg);
24964  sdecode(point2sh(facpt), parentsh);
24965  if (segfacetadjacent(&parentseg, &parentsh)) {
24966  rp = getpointinsradius(parentpt);
24967  if (rv < (sqrt(2.0) * rp)) {
24968  rv = sqrt(2.0) * rp; // The relaxed insertion radius of 'newpt'.
24969  }
24970  }
24971  } else if (pointtype(parentpt) == FREEFACETVERTEX) {
24972  face parentsh1, parentsh2;
24973  sdecode(point2sh(parentpt), parentsh1);
24974  sdecode(point2sh(facpt), parentsh2);
24975  if (facetfacetadjacent(&parentsh1, &parentsh2)) {
24976  rp = getpointinsradius(parentpt);
24977  if (rv < rp) {
24978  rv = rp; // The relaxed insertion radius of 'newpt'.
24979  }
24980  }
24981  }
24982  setpointinsradius(facpt, rv);
24983 }
24984 
24986 // //
24987 // enqueuesubface() Queue a subface or a subsegment for encroachment chk. //
24988 // //
24990 
24991 void tetgenmesh::enqueuesubface(memorypool *pool, face *chkface)
24992 {
24993  if (!smarktest2ed(*chkface)) {
24994  smarktest2(*chkface); // Only queue it once.
24995  face *queface = (face *) pool->alloc();
24996  *queface = *chkface;
24997  }
24998 }
24999 
25001 // //
25002 // enqueuetetrahedron() Queue a tetrahedron for quality check. //
25003 // //
25005 
25006 void tetgenmesh::enqueuetetrahedron(triface *chktet)
25007 {
25008  if (!marktest2ed(*chktet)) {
25009  marktest2(*chktet); // Only queue it once.
25010  triface *quetet = (triface *) badtetrahedrons->alloc();
25011  *quetet = *chktet;
25012  }
25013 }
25014 
25016 // //
25017 // checkseg4encroach() Check if an edge is encroached upon by a point. //
25018 // //
25020 
25021 int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
25022 {
25023  // Check if the point lies inside the diametrical sphere of this seg.
25024  REAL v1[3], v2[3];
25025 
25026  v1[0] = pa[0] - checkpt[0];
25027  v1[1] = pa[1] - checkpt[1];
25028  v1[2] = pa[2] - checkpt[2];
25029  v2[0] = pb[0] - checkpt[0];
25030  v2[1] = pb[1] - checkpt[1];
25031  v2[2] = pb[2] - checkpt[2];
25032 
25033  if (dot(v1, v2) < 0) {
25034  // Inside.
25035  if (b->metric) { // -m option.
25036  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
25037  // The projection of 'checkpt' lies inside the segment [a,b].
25038  REAL prjpt[3], u, v, t;
25039  projpt2edge(checkpt, pa, pb, prjpt);
25040  // Interoplate the mesh size at the location 'prjpt'.
25041  u = distance(pa, pb);
25042  v = distance(pa, prjpt);
25043  t = v / u;
25044  // 'u' is the mesh size at 'prjpt'
25045  u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
25046  v = distance(checkpt, prjpt);
25047  if (v < u) {
25048  return 1; // Encroached prot-ball!
25049  }
25050  } else {
25051  return 1; // NO protecting ball. Encroached.
25052  }
25053  } else {
25054  return 1; // Inside! Encroached.
25055  }
25056  }
25057 
25058  return 0;
25059 }
25060 
25062 // //
25063 // checkseg4split() Check if we need to split a segment. //
25064 // //
25065 // A segment needs to be split if it is in the following case: //
25066 // (1) It is encroached by an existing vertex. //
25067 // (2) It has bad quality (too long). //
25068 // (3) Its length is larger than the mesh sizes at its endpoints. //
25069 // //
25070 // Return 1 if it needs to be split, otherwise, return 0. 'pencpt' returns //
25071 // an encroaching point if there exists. 'qflag' returns '1' if the segment //
25072 // has a length larger than the desired edge length. //
25073 // //
25075 
25076 int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
25077 {
25078  REAL ccent[3], len, r;
25079  int i;
25080 
25081  point forg = sorg(*chkseg);
25082  point fdest = sdest(*chkseg);
25083 
25084  // Initialize the return values.
25085  encpt = NULL;
25086  qflag = 0;
25087 
25088  len = distance(forg, fdest);
25089  r = 0.5 * len;
25090  for (i = 0; i < 3; i++) {
25091  ccent[i] = 0.5 * (forg[i] + fdest[i]);
25092  }
25093 
25094  // First check its quality.
25095  if (checkconstraints && (areabound(*chkseg) > 0.0)) {
25096  if (len > areabound(*chkseg)) {
25097  qflag = 1;
25098  return 1;
25099  }
25100  }
25101 
25102  if (b->fixedvolume) {
25103  if ((len * len * len) > b->maxvolume) {
25104  qflag = 1;
25105  return 1;
25106  }
25107  }
25108 
25109  if (b->metric) { // -m option. Check mesh size.
25110  // Check if the ccent lies outside one of the prot.balls at vertices.
25111  if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
25112  ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
25113  qflag = 1; // Enforce mesh size.
25114  return 1;
25115  }
25116  }
25117 
25118 
25119  // Second check if it is encroached.
25120  // Comment: There may exist more than one encroaching points of this segment.
25121  // The 'encpt' returns the one which is closet to it.
25122  triface searchtet, spintet;
25123  point eapex;
25124  REAL d, diff, smdist = 0;
25125  int t1ver;
25126 
25127  sstpivot1(*chkseg, searchtet);
25128  spintet = searchtet;
25129  while (1) {
25130  eapex = apex(spintet);
25131  if (eapex != dummypoint) {
25132  d = distance(ccent, eapex);
25133  diff = d - r;
25134  if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
25135  if (diff < 0) {
25136  // This segment is encroached by eapex.
25137  if (useinsertradius) {
25138  if (encpt == NULL) {
25139  encpt = eapex;
25140  smdist = d;
25141  } else {
25142  // Choose the closet encroaching point.
25143  if (d < smdist) {
25144  encpt = eapex;
25145  smdist = d;
25146  }
25147  }
25148  } else {
25149  encpt = eapex;
25150  break;
25151  }
25152  }
25153  }
25154  fnextself(spintet);
25155  if (spintet.tet == searchtet.tet) break;
25156  } // while (1)
25157 
25158  if (encpt != NULL) {
25159  return 1;
25160  }
25161 
25162  return 0; // No need to split it.
25163 }
25164 
25166 // //
25167 // splitsegment() Split a segment. //
25168 // //
25169 // The segment 'splitseg' is intended to be split. It will be split if it //
25170 // is in one of the following cases: //
25171 // (1) It is encroached by an existing vertex 'encpt != NULL'; or //
25172 // (2) It is in bad quality 'qflag == 1'; or //
25173 // (3) Its length is larger than the mesh sizes at its endpoints. //
25174 // //
25176 
25177 int tetgenmesh::splitsegment(face *splitseg, point encpt, REAL rrp,
25178  point encpt1, point encpt2, int qflag,
25179  int chkencflag)
25180 {
25181 
25182  if (!qflag && smarktest3ed(*splitseg)) {
25183  // Do not try to re-split a marked segment.
25184  return 0;
25185  }
25186 
25187  if (b->nobisect) { // With -Y option.
25188  // Only split this segment if it is allowed to be split.
25189  if (checkconstraints) {
25190  // Check if it has a non-zero length bound.
25191  if (areabound(*splitseg) == 0) {
25192  // It is not allowed. However, if all of facets containing this seg
25193  // is allowed to be split, we still split it.
25194  face parentsh, spinsh;
25195  //splitseg.shver = 0;
25196  spivot(*splitseg, parentsh);
25197  if (parentsh.sh == NULL) {
25198  return 0; // A dangling segment. Do not split it.
25199  }
25200  spinsh = parentsh;
25201  while (1) {
25202  if (areabound(spinsh) == 0) break;
25203  spivotself(spinsh);
25204  if (spinsh.sh == parentsh.sh) break;
25205  if (spinsh.sh == NULL) break; // It belongs to only one facet.
25206  }
25207  if ((!spinsh.sh) || (areabound(spinsh) == 0)) {
25208  // All facets at this seg are not allowed to be split.
25209  return 0; // Do not split it.
25210  }
25211  }
25212  } else {
25213  return 0; // Do not split this segment.
25214  }
25215  } // if (b->nobisect)
25216 
25217  triface searchtet;
25218  face searchsh;
25219  point newpt;
25220  insertvertexflags ivf;
25221 
25222  makepoint(&newpt, FREESEGVERTEX);
25223  getsteinerptonsegment(splitseg, encpt, newpt);
25224 
25225  if (!qflag && !b->cdtrefine) {
25226  // Do not insert the point if it encroaches upon an adjacent segment.
25227  face parentsh;
25228  spivot(*splitseg, parentsh);
25229  if (parentsh.sh != NULL) {
25230  face spinsh, neighsh;
25231  face neighseg;
25232  spinsh = parentsh;
25233  while (1) {
25234  for (int i = 0; i < 2; i++) {
25235  if (i == 0) {
25236  senext(spinsh, neighsh);
25237  } else {
25238  senext2(spinsh, neighsh);
25239  }
25240  if (isshsubseg(neighsh)) {
25241  sspivot(neighsh, neighseg);
25242  if (checkseg4encroach(sorg(neighseg), sdest(neighseg), newpt)) {
25243  pointdealloc(newpt);
25244  return 0; // Do not split this segment.
25245  }
25246  }
25247  } // i
25248  spivotself(spinsh);
25249  if (spinsh.sh == NULL) break;
25250  if (spinsh.sh == parentsh.sh) break;
25251  } // while (1)
25252  }
25253  }
25254 
25255  // Split the segment by the Bowyer-Watson algorithm.
25256  sstpivot1(*splitseg, searchtet);
25257  ivf.iloc = (int) ONEDGE;
25258  ivf.bowywat = 3; // Use Bowyer-Watson, preserve subsegments and subfaces;
25259  ivf.validflag = 1; // Validate the B-W cavity.
25260  ivf.lawson = 2; // Do flips to recover Delaunayness.
25261  ivf.rejflag = 0; // Do not check encroachment of new segments/facets.
25262  if (b->metric) {
25263  ivf.rejflag |= 4; // Do check encroachment of protecting balls.
25264  }
25265  ivf.chkencflag = chkencflag;
25266  ivf.sloc = (int) INSTAR; // ivf.iloc;
25267  ivf.sbowywat = 3; // ivf.bowywat; // Surface mesh options.
25268  ivf.splitbdflag = 1;
25269  ivf.respectbdflag = 1;
25270  ivf.assignmeshsize = b->metric;
25271  ivf.smlenflag = useinsertradius; // Return the closet mesh vertex.
25272 
25273 
25274  if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
25275  st_segref_count++;
25276  if (steinerleft > 0) steinerleft--;
25277  if (useinsertradius) {
25278  save_segmentpoint_insradius(newpt, ivf.parentpt, ivf.smlen);
25279  }
25280  if (flipstack != NULL) {
25281  flipconstraints fc;
25282  fc.chkencflag = chkencflag;
25283  fc.enqflag = 2;
25284  lawsonflip3d(&fc);
25285  unflipqueue->restart();
25286  }
25287  return 1;
25288  } else {
25289  // Point is not inserted.
25290  if (ivf.iloc == (int) NEARVERTEX) {
25291  terminatetetgen(this, 2);
25292  }
25293  pointdealloc(newpt);
25294  // Mark this segment to avoid splitting in the future.
25295  smarktest3(*splitseg);
25296  return 0;
25297  }
25298 }
25299 
25301 // //
25302 // repairencsegs() Repair encroached (sub) segments. //
25303 // //
25305 
25306 void tetgenmesh::repairencsegs(int chkencflag)
25307 {
25308  face *bface;
25309  point encpt = NULL;
25310  int qflag = 0;
25311 
25312  // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
25313  // if an unlimited number of Steiner points is allowed.
25314  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
25315  badsubsegs->traversalinit();
25316  bface = (face *) badsubsegs->traverse();
25317  while ((bface != NULL) && (steinerleft != 0)) {
25318  // Skip a deleleted element.
25319  if (bface->shver >= 0) {
25320  // A queued segment may have been deleted (split).
25321  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25322  // A queued segment may have been processed.
25323  if (smarktest2ed(*bface)) {
25324  sunmarktest2(*bface);
25325  if (checkseg4split(bface, encpt, qflag)) {
25326  splitsegment(bface, encpt, 0, NULL, NULL, qflag, chkencflag);
25327  }
25328  }
25329  }
25330  // Remove this entry from list.
25331  bface->shver = -1; // Signal it as a deleted element.
25332  badsubsegs->dealloc((void *) bface);
25333  }
25334  bface = (face *) badsubsegs->traverse();
25335  }
25336  }
25337 
25338  if (badsubsegs->items > 0) {
25339  if (b->verbose) {
25340  printf("The desired number of Steiner points is reached.\n");
25341  }
25342  badsubsegs->traversalinit();
25343  bface = (face *) badsubsegs->traverse();
25344  while (bface != NULL) {
25345  // Skip a deleleted element.
25346  if (bface->shver >= 0) {
25347  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25348  if (smarktest2ed(*bface)) {
25349  sunmarktest2(*bface);
25350  }
25351  }
25352  }
25353  bface = (face *) badsubsegs->traverse();
25354  }
25355  badsubsegs->restart();
25356  }
25357 }
25358 
25360 // //
25361 // checkfac4encroach() Check if a subface is encroached by a point. //
25362 // //
25364 
25365 int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
25366  REAL* cent, REAL* r)
25367 {
25368  REAL rd, len;
25369  int encroached = 0;
25370 
25371  circumsphere(pa, pb, pc, NULL, cent, &rd);
25372  if (rd == 0) {
25373  terminatetetgen(this, 2);
25374  }
25375 
25376  if (b->use_equatorial_lens) {
25377  REAL normal[3], fcenter[3];
25378  REAL xta, yta, zta;
25379  REAL multiplier;
25380 
25381  fcenter[0] = cent[0] - pc[0];
25382  fcenter[1] = cent[1] - pc[1];
25383  fcenter[2] = cent[2] - pc[2];
25384 
25385  // Get the normal of the oriented face [a->b->c], without normalized.
25386  facenormal(pa, pb, pc, normal, 1, NULL);
25387  multiplier = 0.985 * sqrt((fcenter[0]*fcenter[0] + fcenter[1]*fcenter[1] +
25388  fcenter[2]*fcenter[2]) /
25389  (3.0 * (normal[0] * normal[0] + normal[1] * normal[1] +
25390  normal[2] * normal[2])));
25391  xta = checkpt[0] - pc[0];
25392  yta = checkpt[1] - pc[1];
25393  zta = checkpt[2] - pc[2];
25394  // Make sure that the normal is pointing to "checkpt".
25395  if ((xta * normal[0] + yta * normal[1] + zta * normal[2]) < 0) {
25396  // Reverse the normal direction.
25397  normal[0] = -normal[0];
25398  normal[1] = -normal[1];
25399  normal[2] = -normal[2];
25400  }
25401 
25402  if (xta * xta + yta * yta + zta * zta <=
25403  2.0 * (xta * (fcenter[0] - multiplier * normal[0]) +
25404  yta * (fcenter[1] - multiplier * normal[1]) +
25405  zta * (fcenter[2] - multiplier * normal[2]))) {
25406  encroached = 1;
25407  }
25408  } else {
25409  len = distance(cent, checkpt);
25410  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
25411  if (len < rd) {
25412  encroached = 1;
25413  }
25414  }
25415 
25416  if (encroached) {
25417  // The point lies inside the circumsphere of this face.
25418  if (b->metric) { // -m option.
25419  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
25420  (pc[pointmtrindex] > 0)) {
25421  // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
25422  REAL prjpt[3], n[3];
25423  REAL a, a1, a2, a3;
25424  projpt2face(checkpt, pa, pb, pc, prjpt);
25425  // Get the face area of [a,b,c].
25426  facenormal(pa, pb, pc, n, 1, NULL);
25427  a = sqrt(dot(n,n));
25428  // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
25429  facenormal(pa, pb, prjpt, n, 1, NULL);
25430  a1 = sqrt(dot(n,n));
25431  facenormal(pb, pc, prjpt, n, 1, NULL);
25432  a2 = sqrt(dot(n,n));
25433  facenormal(pc, pa, prjpt, n, 1, NULL);
25434  a3 = sqrt(dot(n,n));
25435  if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
25436  // This face contains the projection.
25437  // Get the mesh size at the location of the projection point.
25438  rd = a1 / a * pc[pointmtrindex]
25439  + a2 / a * pa[pointmtrindex]
25440  + a3 / a * pb[pointmtrindex];
25441  len = distance(prjpt, checkpt);
25442  if (len < rd) {
25443  return 1; // Encroached.
25444  }
25445  }
25446  } else {
25447  return 1; // No protecting ball. Encroached.
25448  }
25449  } else {
25450  *r = rd;
25451  return 1; // Encroached.
25452  }
25453  }
25454 
25455  return 0;
25456 }
25457 
25459 // //
25460 // checkfac4split() Check if a subface needs to be split. //
25461 // //
25462 // A subface needs to be split if it is in the following case: //
25463 // (1) It is encroached by an existing vertex. //
25464 // (2) It has bad quality (has a small angle, -q). //
25465 // (3) It's area is larger than a prescribed value (.var). //
25466 // //
25467 // Return 1 if it needs to be split, otherwise, return 0. //
25468 // 'chkfac' represents its longest edge. //
25469 // //
25471 
25472 int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
25473  REAL *cent)
25474 {
25475  point pa, pb, pc;
25476  REAL area, rd, len;
25477  REAL A[4][4], rhs[4], D;
25478  int indx[4];
25479  int i;
25480 
25481  encpt = NULL;
25482  qflag = 0;
25483 
25484  pa = sorg(*chkfac);
25485  pb = sdest(*chkfac);
25486  pc = sapex(*chkfac);
25487 
25488  // Compute the coefficient matrix A (3x3).
25489  A[0][0] = pb[0] - pa[0];
25490  A[0][1] = pb[1] - pa[1];
25491  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
25492  A[1][0] = pc[0] - pa[0];
25493  A[1][1] = pc[1] - pa[1];
25494  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
25495  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
25496 
25497  area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
25498 
25499  // Compute the right hand side vector b (3x1).
25500  rhs[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
25501  rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
25502  rhs[2] = 0.0;
25503 
25504  // Solve the 3 by 3 equations use LU decomposition with partial
25505  // pivoting and backward and forward substitute.
25506  if (!lu_decmp(A, 3, indx, &D, 0)) {
25507  // A degenerate triangle.
25508  terminatetetgen(this, 2);
25509  }
25510 
25511  lu_solve(A, 3, indx, rhs, 0);
25512  cent[0] = pa[0] + rhs[0];
25513  cent[1] = pa[1] + rhs[1];
25514  cent[2] = pa[2] + rhs[2];
25515  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
25516 
25517  if (checkconstraints && (areabound(*chkfac) > 0.0)) {
25518  // Check if the subface has too big area.
25519  if (area > areabound(*chkfac)) {
25520  qflag = 1;
25521  return 1;
25522  }
25523  }
25524 
25525  if (b->fixedvolume) {
25526  if ((area * sqrt(area)) > b->maxvolume) {
25527  qflag = 1;
25528  return 1;
25529  }
25530  }
25531 
25532  if (b->varvolume) {
25533  triface adjtet;
25534  REAL volbnd;
25535  int t1ver;
25536 
25537  stpivot(*chkfac, adjtet);
25538  if (!ishulltet(adjtet)) {
25539  volbnd = volumebound(adjtet.tet);
25540  if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
25541  qflag = 1;
25542  return 1;
25543  }
25544  }
25545  fsymself(adjtet);
25546  if (!ishulltet(adjtet)) {
25547  volbnd = volumebound(adjtet.tet);
25548  if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
25549  qflag = 1;
25550  return 1;
25551  }
25552  }
25553  }
25554 
25555  if (b->metric) { // -m option. Check mesh size.
25556  // Check if the ccent lies outside one of the prot.balls at vertices.
25557  if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
25558  ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
25559  ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
25560  qflag = 1; // Enforce mesh size.
25561  return 1;
25562  }
25563  }
25564 
25565  triface searchtet;
25566  REAL smlen = 0;
25567 
25568  // Check if this subface is locally encroached.
25569  for (i = 0; i < 2; i++) {
25570  stpivot(*chkfac, searchtet);
25571  if (!ishulltet(searchtet)) {
25572  int encroached = 0;
25573 
25574  len = distance(oppo(searchtet), cent);
25575  if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
25576 
25577  if (b->use_equatorial_lens) {
25578  point tettapex = oppo(searchtet);
25579  REAL normal[3], fcenter[3];
25580  REAL xta, yta, zta;
25581  REAL multiplier;
25582  // Get the normal of the oriented face [a->b->c], without normalized.
25583  point fa = org(searchtet);
25584  point fb = dest(searchtet);
25585  point fc = apex(searchtet);
25586 
25587  fcenter[0] = cent[0] - fc[0];
25588  fcenter[1] = cent[1] - fc[1];
25589  fcenter[2] = cent[2] - fc[2];
25590 
25591  facenormal(fa, fb, fc, normal, 1, NULL);
25592  multiplier = 0.985 * sqrt((fcenter[0]*fcenter[0] + fcenter[1]*fcenter[1] +
25593  fcenter[2]*fcenter[2]) /
25594  (3.0 * (normal[0] * normal[0] + normal[1] * normal[1] +
25595  normal[2] * normal[2])));
25596  xta = tettapex[0] - fc[0];
25597  yta = tettapex[1] - fc[1];
25598  zta = tettapex[2] - fc[2];
25599  if (xta * xta + yta * yta + zta * zta <=
25600  2.0 * (xta * (fcenter[0] - multiplier * normal[0]) +
25601  yta * (fcenter[1] - multiplier * normal[1]) +
25602  zta * (fcenter[2] - multiplier * normal[2]))) {
25603  encroached = 1;
25604  }
25605  } else {
25606  if (len < rd) {
25607  encroached = 1;
25608  }
25609  }
25610 
25611  if (encroached) {
25612  if (smlen == 0) {
25613  smlen = len;
25614  encpt = oppo(searchtet);
25615  } else {
25616  if (len < smlen) {
25617  smlen = len;
25618  encpt = oppo(searchtet);
25619  }
25620  }
25621  //return 1;
25622  }
25623  }
25624  sesymself(*chkfac);
25625  }
25626 
25627  return encpt != NULL; //return 0;
25628 }
25629 
25631 // //
25632 // splitsubface() Split a subface. //
25633 // //
25634 // The subface may be encroached, or in bad-quality. It is split at its cir- //
25635 // cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg- //
25636 // ment. Instead, one of the encroached segments is split. It is possible //
25637 // that none of the encroached segments can be split. //
25638 // //
25639 // The return value indicates whether a new point is inserted (> 0) or not //
25640 // (= 0). Furthermore, it is inserted on an encroached segment (= 1) or //
25641 // in-side the facet (= 2). //
25642 // //
25643 // 'encpt' is a vertex encroaching upon this subface, i.e., it causes the //
25644 // split of this subface. If 'encpt' is NULL, then the cause of the split //
25645 // this subface is a rejected tet circumcenter 'p', and 'encpt1' is the //
25646 // parent of 'p'. //
25647 // //
25649 
25650 int tetgenmesh::splitsubface(face *splitfac, point encpt, point encpt1,
25651  int qflag, REAL *ccent, int chkencflag)
25652 {
25653 
25654  if (!qflag && smarktest3ed(*splitfac)) {
25655  // Do not try to re-split a marked subface.
25656  return 0;
25657  }
25658 
25659  if (b->nobisect) { // With -Y option.
25660  if (checkconstraints) {
25661  // Only split if it is allowed to be split.
25662  // Check if this facet has a non-zero constraint.
25663  if (areabound(*splitfac) == 0) {
25664  return 0; // Do not split it.
25665  }
25666  } else {
25667  return 0;
25668  }
25669  } // if (b->nobisect)
25670 
25671  if (useinsertradius) {
25672  if (encpt != NULL) {
25673  REAL rp; // Insertion radius of newpt.
25674  REAL rv = distance(encpt, ccent);
25675  if (pointtype(encpt) == FREESEGVERTEX) {
25676  face parentseg;
25677  sdecode(point2sh(encpt), parentseg);
25678  if (segfacetadjacent(&parentseg, splitfac)) {
25679  rp = getpointinsradius(encpt);
25680  if (rv < (sqrt(2.0) * rp)) {
25681  // This insertion may cause no termination.
25682  return 0; // Reject the insertion of newpt.
25683  }
25684  }
25685  } else if (pointtype(encpt) == FREEFACETVERTEX) {
25686  face parentsh;
25687  sdecode(point2sh(encpt), parentsh);
25688  if (facetfacetadjacent(&parentsh, splitfac)) {
25689  rp = getpointinsradius(encpt);
25690  if (rv < rp) {
25691  return 0; // Reject the insertion of newpt.
25692  }
25693  }
25694  }
25695  }
25696  } // if (useinsertradius)
25697 
25698  face searchsh;
25699  insertvertexflags ivf;
25700  point newpt;
25701  int i;
25702 
25703  // Initialize the inserting point.
25704  makepoint(&newpt, FREEFACETVERTEX);
25705  // Split the subface at its circumcenter.
25706  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
25707 
25708  // Search a subface which contains 'newpt'.
25709  searchsh = *splitfac;
25710  // Calculate an above point. It lies above the plane containing
25711  // the subface [a,b,c], and save it in dummypoint. Moreover,
25712  // the vector cent->dummypoint is the normal of the plane.
25713  calculateabovepoint4(newpt, sorg(*splitfac), sdest(*splitfac),
25714  sapex(*splitfac));
25715  // Parameters: 'aflag' = 1, - above point exists.
25716  // 'cflag' = 0, - non-convex, check co-planarity of the result.
25717  // 'rflag' = 0, - no need to round the locating result.
25718  ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
25719 
25720  if (!((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE))) {
25721  // Point location failed.
25722  pointdealloc(newpt);
25723  // Mark this subface to avoid splitting in the future.
25724  smarktest3(*splitfac);
25725  return 0;
25726  }
25727 
25728 
25729  triface searchtet;
25730 
25731  // Insert the point.
25732  stpivot(searchsh, searchtet);
25733  ivf.bowywat = 3; // Use Bowyer-Watson. Preserve subsegments and subfaces;
25734  ivf.lawson = 2;
25735  ivf.rejflag = 1; // Do check the encroachment of segments.
25736  if (b->metric) {
25737  ivf.rejflag |= 4; // Do check encroachment of protecting balls.
25738  }
25739  ivf.chkencflag = chkencflag;
25740  ivf.sloc = (int) INSTAR; // ivf.iloc;
25741  ivf.sbowywat = 3; // ivf.bowywat;
25742  ivf.splitbdflag = 1;
25743  ivf.validflag = 1;
25744  ivf.respectbdflag = 1;
25745  ivf.assignmeshsize = b->metric;
25746  ivf.refineflag = 2;
25747  ivf.refinesh = *splitfac;
25748  ivf.smlenflag = useinsertradius; // Update the insertion radius.
25749 
25750 
25751  if (insertpoint(newpt, &searchtet, &searchsh, NULL, &ivf)) {
25752  st_facref_count++;
25753  if (steinerleft > 0) steinerleft--;
25754  if (useinsertradius) {
25755  save_facetpoint_insradius(newpt, ivf.parentpt, ivf.smlen);
25756  } // if (useinsertradius)
25757  if (flipstack != NULL) {
25758  flipconstraints fc;
25759  fc.chkencflag = chkencflag;
25760  fc.enqflag = 2;
25761  lawsonflip3d(&fc);
25762  unflipqueue->restart();
25763  }
25764  return 1;
25765  } else {
25766  // Point was not inserted.
25767  pointdealloc(newpt);
25768  if (ivf.iloc == (int) ENCSEGMENT) {
25769  // Select an encroached segment and split it.
25770  face *paryseg;
25771  int splitflag = 0;
25772  for (i = 0; i < encseglist->objects; i++) {
25773  paryseg = (face *) fastlookup(encseglist, i);
25774  if (splitsegment(paryseg, NULL, 0.0, encpt, encpt1, qflag,
25775  chkencflag | 1)) {
25776  splitflag = 1; // A point is inserted on a segment.
25777  break;
25778  }
25779  } // i
25780  encseglist->restart();
25781  if (splitflag) {
25782  // Some segments may need to be repaired.
25783  if (badsubsegs->items > 0) {
25784  repairencsegs(chkencflag | 1);
25785  }
25786  return 1;
25787  }
25788  } else {
25789  if (ivf.iloc == (int) NEARVERTEX) {
25790  terminatetetgen(this, 2);
25791  }
25792  }
25793  // Mark this subface to avoid splitting in the future.
25794  smarktest3(*splitfac);
25795  return 0;
25796  }
25797 }
25798 
25800 // //
25801 // repairencfacs() Repair encroached subfaces. //
25802 // //
25804 
25805 void tetgenmesh::repairencfacs(int chkencflag)
25806 {
25807  face *bface;
25808  point encpt = NULL;
25809  int qflag = 0;
25810  REAL ccent[3];
25811 
25812  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
25813  // if an unlimited number of Steiner points is allowed.
25814  while ((badsubfacs->items > 0) && (steinerleft != 0)) {
25815  badsubfacs->traversalinit();
25816  bface = (face *) badsubfacs->traverse();
25817  while ((bface != NULL) && (steinerleft != 0)) {
25818  // Skip a deleted element.
25819  if (bface->shver >= 0) {
25820  // A queued subface may have been deleted (split).
25821  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25822  // A queued subface may have been processed.
25823  if (smarktest2ed(*bface)) {
25824  sunmarktest2(*bface);
25825  if (checkfac4split(bface, encpt, qflag, ccent)) {
25826  splitsubface(bface, encpt, NULL, qflag, ccent, chkencflag);
25827  }
25828  }
25829  }
25830  bface->shver = -1; // Signal it as a deleted element.
25831  badsubfacs->dealloc((void *) bface); // Remove this entry from list.
25832  }
25833  bface = (face *) badsubfacs->traverse();
25834  }
25835  }
25836 
25837  if (badsubfacs->items > 0) {
25838  if (steinerleft == 0) {
25839  if (b->verbose) {
25840  printf("The desired number of Steiner points is reached.\n");
25841  }
25842  } else {
25843  terminatetetgen(this, 2);
25844  }
25845  badsubfacs->traversalinit();
25846  bface = (face *) badsubfacs->traverse();
25847  while (bface != NULL) {
25848  // Skip a deleted element.
25849  if (bface->shver >= 0) {
25850  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25851  if (smarktest2ed(*bface)) {
25852  sunmarktest2(*bface);
25853  }
25854  }
25855  }
25856  bface = (face *) badsubfacs->traverse();
25857  }
25858  badsubfacs->restart();
25859  }
25860 }
25861 
25863 // //
25864 // checktet4split() Check if the tet needs to be split. //
25865 // //
25867 
25868 int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
25869 {
25870  point pa, pb, pc, pd, *ppt;
25871  REAL vda[3], vdb[3], vdc[3];
25872  REAL vab[3], vbc[3], vca[3];
25873  REAL N[4][3], L[4], cosd[6], elen[6];
25874  REAL maxcosd, vol, volbnd, smlen = 0, rd;
25875  REAL A[4][4], rhs[4], D;
25876  int indx[4];
25877  int i, j;
25878 
25879  if (b->convex) { // -c
25880  // Skip this tet if it lies in the exterior.
25881  if (elemattribute(chktet->tet, numelemattrib - 1) == -1.0) {
25882  return 0;
25883  }
25884  }
25885 
25886  qflag = 0;
25887 
25888  pd = (point) chktet->tet[7];
25889  if (pd == dummypoint) {
25890  return 0; // Do not split a hull tet.
25891  }
25892 
25893  pa = (point) chktet->tet[4];
25894  pb = (point) chktet->tet[5];
25895  pc = (point) chktet->tet[6];
25896 
25897  // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
25898  // Set the matrix A = [vda, vdb, vdc]^T.
25899  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
25900  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
25901  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
25902 
25903  // Get the other edge vectors.
25904  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
25905  for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
25906  for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
25907 
25908  if (!lu_decmp(A, 3, indx, &D, 0)) {
25909  // A degenerated tet (vol = 0).
25910  // This is possible due to the use of exact arithmetic. We temporarily
25911  // leave this tet. It should be fixed by mesh optimization.
25912  return 0;
25913  }
25914 
25915  // Check volume if '-a#' and '-a' options are used.
25916  if (b->varvolume || b->fixedvolume) {
25917  vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
25918  if (b->fixedvolume) {
25919  if (vol > b->maxvolume) {
25920  qflag = 1;
25921  }
25922  }
25923  if (!qflag && b->varvolume) {
25924  volbnd = volumebound(chktet->tet);
25925  if ((volbnd > 0.0) && (vol > volbnd)) {
25926  qflag = 1;
25927  }
25928  }
25929  if (qflag == 1) {
25930  // Calculate the circumcenter of this tet.
25931  rhs[0] = 0.5 * dot(vda, vda);
25932  rhs[1] = 0.5 * dot(vdb, vdb);
25933  rhs[2] = 0.5 * dot(vdc, vdc);
25934  lu_solve(A, 3, indx, rhs, 0);
25935  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25936  return 1;
25937  }
25938  }
25939 
25940  if (b->metric) { // -m option. Check mesh size.
25941  // Calculate the circumradius of this tet.
25942  rhs[0] = 0.5 * dot(vda, vda);
25943  rhs[1] = 0.5 * dot(vdb, vdb);
25944  rhs[2] = 0.5 * dot(vdc, vdc);
25945  lu_solve(A, 3, indx, rhs, 0);
25946  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25947  rd = sqrt(dot(rhs, rhs));
25948  // Check if the ccent lies outside one of the prot.balls at vertices.
25949  ppt = (point *) &(chktet->tet[4]);
25950  for (i = 0; i < 4; i++) {
25951  if (ppt[i][pointmtrindex] > 0) {
25952  if (rd > ppt[i][pointmtrindex]) {
25953  qflag = 1; // Enforce mesh size.
25954  return 1;
25955  }
25956  }
25957  }
25958  }
25959 
25960  if (in->tetunsuitable != NULL) {
25961  // Execute the user-defined meshing sizing evaluation.
25962  if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
25963  // Calculate the circumcenter of this tet.
25964  rhs[0] = 0.5 * dot(vda, vda);
25965  rhs[1] = 0.5 * dot(vdb, vdb);
25966  rhs[2] = 0.5 * dot(vdc, vdc);
25967  lu_solve(A, 3, indx, rhs, 0);
25968  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25969  return 1;
25970  }
25971  }
25972 
25973  if (useinsertradius) {
25974  // Do not split this tet if the shortest edge is shorter than the
25975  // insertion radius of one of its endpoints.
25976  triface checkedge;
25977  point e1, e2;
25978  REAL rrv, smrrv;
25979 
25980  // Get the shortest edge of this tet.
25981  checkedge.tet = chktet->tet;
25982  for (i = 0; i < 6; i++) {
25983  checkedge.ver = edge2ver[i];
25984  e1 = org(checkedge);
25985  e2 = dest(checkedge);
25986  elen[i] = distance(e1, e2);
25987  if (i == 0) {
25988  smlen = elen[i];
25989  j = 0;
25990  } else {
25991  if (elen[i] < smlen) {
25992  smlen = elen[i];
25993  j = i;
25994  }
25995  }
25996  }
25997  // Check if the edge is too short.
25998  checkedge.ver = edge2ver[j];
25999  // Get the smallest rrv of e1 and e2.
26000  // Note: if rrv of e1 and e2 is zero. Do not use it.
26001  e1 = org(checkedge);
26002  smrrv = getpointinsradius(e1);
26003  e2 = dest(checkedge);
26004  rrv = getpointinsradius(e2);
26005  if (rrv > 0) {
26006  if (smrrv > 0) {
26007  if (rrv < smrrv) {
26008  smrrv = rrv;
26009  }
26010  } else {
26011  smrrv = rrv;
26012  }
26013  }
26014  if (smrrv > 0) {
26015  // To avoid rounding error, round smrrv before doing comparison.
26016  if ((fabs(smrrv - smlen) / smlen) < b->epsilon) {
26017  smrrv = smlen;
26018  }
26019  if (smrrv > smlen) {
26020  return 0;
26021  }
26022  }
26023  } // if (useinsertradius)
26024 
26025  // Check the radius-edge ratio. Set by -q#.
26026  if (b->minratio > 0) {
26027  // Calculate the circumcenter and radius of this tet.
26028  rhs[0] = 0.5 * dot(vda, vda);
26029  rhs[1] = 0.5 * dot(vdb, vdb);
26030  rhs[2] = 0.5 * dot(vdc, vdc);
26031  lu_solve(A, 3, indx, rhs, 0);
26032  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
26033  rd = sqrt(dot(rhs, rhs));
26034  if (!useinsertradius) {
26035  // Calculate the shortest edge length.
26036  elen[0] = dot(vda, vda);
26037  elen[1] = dot(vdb, vdb);
26038  elen[2] = dot(vdc, vdc);
26039  elen[3] = dot(vab, vab);
26040  elen[4] = dot(vbc, vbc);
26041  elen[5] = dot(vca, vca);
26042  smlen = elen[0]; //sidx = 0;
26043  for (i = 1; i < 6; i++) {
26044  if (smlen > elen[i]) {
26045  smlen = elen[i]; //sidx = i;
26046  }
26047  }
26048  smlen = sqrt(smlen);
26049  }
26050  D = rd / smlen;
26051  if (D > b->minratio) {
26052  // A bad radius-edge ratio.
26053  return 1;
26054  }
26055  }
26056 
26057  // Check the minimum dihedral angle. Set by -qq#.
26058  if (b->mindihedral > 0) {
26059  // Compute the 4 face normals (N[0], ..., N[3]).
26060  for (j = 0; j < 3; j++) {
26061  for (i = 0; i < 3; i++) N[j][i] = 0.0;
26062  N[j][j] = 1.0; // Positive means the inside direction
26063  lu_solve(A, 3, indx, N[j], 0);
26064  }
26065  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
26066  // Normalize the normals.
26067  for (i = 0; i < 4; i++) {
26068  L[i] = sqrt(dot(N[i], N[i]));
26069  if (L[i] == 0) {
26070  terminatetetgen(this, 2);
26071  }
26072  for (j = 0; j < 3; j++) N[i][j] /= L[i];
26073  }
26074  // Calculate the six dihedral angles.
26075  cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
26076  cosd[1] = -dot(N[0], N[2]);
26077  cosd[2] = -dot(N[0], N[3]);
26078  cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
26079  cosd[4] = -dot(N[1], N[3]);
26080  cosd[5] = -dot(N[2], N[3]); // Edge ab
26081  // Get the smallest dihedral angle.
26082  //maxcosd = mincosd = cosd[0];
26083  maxcosd = cosd[0];
26084  for (i = 1; i < 6; i++) {
26085  //if (cosd[i] > maxcosd) maxcosd = cosd[i];
26086  maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
26087  //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
26088  }
26089  if (maxcosd > cosmindihed) {
26090  // Calculate the circumcenter of this tet.
26091  // A bad dihedral angle.
26092  //if ((b->quality & 1) == 0) {
26093  rhs[0] = 0.5 * dot(vda, vda);
26094  rhs[1] = 0.5 * dot(vdb, vdb);
26095  rhs[2] = 0.5 * dot(vdc, vdc);
26096  lu_solve(A, 3, indx, rhs, 0);
26097  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
26098  //*rd = sqrt(dot(rhs, rhs));
26099  //}
26100  return 1;
26101  }
26102  }
26103 
26104  return 0;
26105 }
26106 
26108 // //
26109 // splittetrahedron() Split a tetrahedron. //
26110 // //
26112 
26113 int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
26114  int chkencflag)
26115 {
26116  triface searchtet;
26117  face *paryseg;
26118  point newpt, *ppt;
26119  badface *bface;
26120  insertvertexflags ivf;
26121  int splitflag = 0;
26122  int i;
26123 
26124 
26125 
26126  REAL rv = 0.; // Insertion radius of 'newpt'.
26127 
26128  makepoint(&newpt, FREEVOLVERTEX);
26129  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
26130 
26131 
26132  // Locate the new point. Starting from an interior point 'q' of the
26133  // splittet. We perform a walk from q to the 'newpt', stop walking
26134  // either we hit a subface or enter OUTSIDE.
26135  searchtet = *splittet;
26136  ivf.iloc = (int) OUTSIDE;
26137  ivf.iloc = locate(newpt, &searchtet, 1); // 'chkencflag' = 1.
26138 
26139  if ((ivf.iloc == (int) OUTSIDE) || (ivf.iloc == (int) ENCSUBFACE)) {
26140  // The circumcenter 'c' is not visible from 'q' (the interior of the tet).
26141 // iffalse
26142  if (b->verbose > 2) {
26143  printf(" New point %d is blocked by a polygon.\n", pointmark(newpt));
26144  }
26145 // \fi
26146  pointdealloc(newpt); // Do not insert this vertex.
26147  if (b->nobisect) return 0; // -Y option.
26148  // There must be a polygon that blocks the visibility.
26149  // Search a subpolygon that contains the proj(c).
26150  face searchsh;
26151  REAL prjpt[3];
26152  locateresult sloc = OUTSIDE;
26153  tspivot(searchtet, searchsh);
26154  ppt = (point *) &(searchsh.sh[3]);
26155  projpt2face(ccent, ppt[0], ppt[1], ppt[2], prjpt);
26156  // Locate proj(c) on polygon.
26157  sloc = slocate(prjpt, &searchsh, 0, 0, 1);
26158  if ((sloc == ONEDGE) || (sloc == ONFACE)) {
26159  // Found a subface/edge containing proj(c).
26160  // Check if 'c' encoraches upon this subface.
26161  REAL fcent[3], r = 0;
26162  ppt = (point *) &(searchsh.sh[3]);
26163  if (checkfac4encroach(ppt[0], ppt[1], ppt[2], ccent, fcent, &r)) {
26164  // Encroached. Split this subface.
26165  splitflag = splitsubface(&searchsh, NULL, org(*splittet), qflag,
26166  fcent, chkencflag | 2);
26167  if (splitflag) {
26168  // Some subfaces may need to be repaired.
26169  repairencfacs(chkencflag | 2);
26170  }
26171  }
26172  }
26173  else if ((sloc == OUTSIDE) || (sloc == ENCSEGMENT)) {
26174  // Hit a segment. We should split it.
26175  // To be done...
26176  // printf("hit segment, split it.\n"); // For debug only
26177  }
26178  if (splitflag) {
26179  // Queue the tet if it is still alive.
26180  if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
26181  enqueuetetrahedron(splittet);
26182  }
26183  }
26184  return splitflag;
26185  }
26186 
26187 
26188 
26189  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
26190  ivf.bowywat = 3;
26191  ivf.lawson = 2;
26192  ivf.rejflag = 3; // Do check for encroached segments and subfaces.
26193  if (b->metric) {
26194  ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
26195  }
26196  ivf.chkencflag = chkencflag;
26197  ivf.sloc = ivf.sbowywat = 0; // No use.
26198  ivf.splitbdflag = 0; // No use.
26199  ivf.validflag = 1;
26200  ivf.respectbdflag = 1;
26201  ivf.assignmeshsize = b->metric;
26202 
26203  ivf.refineflag = 1;
26204  ivf.refinetet = *splittet;
26205  if (useinsertradius) {
26206  // Need to save insertion radius for this new point.
26207  ivf.smlenflag = 1; // Return the shortest edge length after inserting
26208  // the new vertex. [2016-09-19]
26209  }
26210 
26211 
26212  if (insertpoint(newpt, &searchtet, NULL, NULL, &ivf)) {
26213  // Vertex is inserted.
26214  st_volref_count++;
26215  if (steinerleft > 0) steinerleft--;
26216  if (useinsertradius) {
26217  setpointinsradius(newpt, ivf.smlen);
26218  setpoint2ppt(newpt, ivf.parentpt);
26219  }
26220  if (flipstack != NULL) {
26221  flipconstraints fc;
26222  fc.chkencflag = chkencflag;
26223  fc.enqflag = 2;
26224  lawsonflip3d(&fc);
26225  unflipqueue->restart();
26226  }
26227  return 1;
26228  } else {
26229  // Point is not inserted.
26230  pointdealloc(newpt);
26231  // Check if there are encroached segments/subfaces.
26232  if (ivf.iloc == (int) ENCSEGMENT) {
26233  if (!b->nobisect || checkconstraints) {
26234  // Select an encroached segment and split it.
26235  for (i = 0; i < encseglist->objects; i++) {
26236  paryseg = (face *) fastlookup(encseglist, i);
26237  if (splitsegment(paryseg, NULL, rv, org(*splittet), NULL, qflag,
26238  chkencflag | 3)) {
26239  splitflag = 1; // A point is inserted on a segment.
26240  break;
26241  }
26242  }
26243  } // if (!b->nobisect)
26244  encseglist->restart();
26245  if (splitflag) {
26246  // Some segments may need to be repaired.
26247  if (badsubsegs->items > 0) {
26248  repairencsegs(chkencflag | 3);
26249  }
26250  // Some subfaces may need to be repaired.
26251  if (badsubfacs->items > 0) {
26252  repairencfacs(chkencflag | 2);
26253  }
26254  }
26255  } else if (ivf.iloc == (int) ENCSUBFACE) {
26256  if (!b->nobisect || checkconstraints) {
26257  // Select an encroached subface and split it.
26258  for (i = 0; i < encshlist->objects; i++) {
26259  bface = (badface *) fastlookup(encshlist, i);
26260  if (splitsubface(&(bface->ss), NULL, org(*splittet), qflag,
26261  bface->cent, chkencflag | 2)){
26262  splitflag = 1; // A point is inserted on a subface or a segment.
26263  break;
26264  }
26265  }
26266  } // if (!b->nobisect)
26267  encshlist->restart();
26268  if (splitflag) {
26269  // Some subfaces may need to be repaired.
26270  if (badsubfacs->items > 0) {
26271  repairencfacs(chkencflag | 2);
26272  }
26273  }
26274  } else {
26275  if (ivf.iloc == (int) NEARVERTEX) {
26276  terminatetetgen(this, 2);
26277  }
26278  }
26279  if (splitflag) {
26280  // Queue the tet if it is still alive.
26281  if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
26282  enqueuetetrahedron(splittet);
26283  }
26284  } else {
26285  //assert(0); // If no small angle, why can this happen?
26286  }
26287  return splitflag;
26288  }
26289 }
26290 
26292 // //
26293 // repairbadtets() Repair bad quality tetrahedra. //
26294 // //
26296 
26297 void tetgenmesh::repairbadtets(int chkencflag)
26298 {
26299  triface *bface;
26300  REAL ccent[3];
26301  int qflag = 0;
26302 
26303 
26304  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
26305  // if an unlimited number of Steiner points is allowed.
26306  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
26307  badtetrahedrons->traversalinit();
26308  bface = (triface *) badtetrahedrons->traverse();
26309  while ((bface != NULL) && (steinerleft != 0)) {
26310  // Skip a deleted element.
26311  if (bface->ver >= 0) {
26312  // A queued tet may have been deleted.
26313  if (!isdeadtet(*bface)) {
26314  // A queued tet may have been processed.
26315  if (marktest2ed(*bface)) {
26316  unmarktest2(*bface);
26317  if (checktet4split(bface, qflag, ccent)) {
26318  splittetrahedron(bface, qflag, ccent, chkencflag);
26319  }
26320  }
26321  }
26322  bface->ver = -1; // Signal it as a deleted element.
26323  badtetrahedrons->dealloc((void *) bface);
26324  }
26325  bface = (triface *) badtetrahedrons->traverse();
26326  }
26327  }
26328 
26329  if (badtetrahedrons->items > 0) {
26330  if (steinerleft == 0) {
26331  if (b->verbose) {
26332  printf("The desired number of Steiner points is reached.\n");
26333  }
26334  } else {
26335  terminatetetgen(this, 2); // Unknown case.
26336  }
26337  // Unmark all queued tet.
26338  badtetrahedrons->traversalinit();
26339  bface = (triface *) badtetrahedrons->traverse();
26340  while (bface != NULL) {
26341  // Skip a deleted element.
26342  if (bface->ver >= 0) {
26343  if (!isdeadtet(*bface)) {
26344  if (marktest2ed(*bface)) {
26345  unmarktest2(*bface);
26346  }
26347  }
26348  }
26349  bface = (triface *) badtetrahedrons->traverse();
26350  }
26351  // Clear the pool.
26352  badtetrahedrons->restart();
26353  }
26354 }
26355 
26357 // //
26358 // delaunayrefinement() Refine the mesh by Delaunay refinement. //
26359 // //
26361 
26362 void tetgenmesh::delaunayrefinement()
26363 {
26364  triface checktet;
26365  face checksh;
26366  face checkseg;
26367  long steinercount;
26368  int chkencflag;
26369 
26370  long bak_segref_count, bak_facref_count, bak_volref_count;
26371  long bak_flipcount = flip23count + flip32count + flip44count;
26372 
26373  if (!b->quiet) {
26374  printf("Refining mesh...\n");
26375  }
26376 
26377  if (b->verbose) {
26378  printf(" Min radius-edge ratio = %g.\n", b->minratio);
26379  printf(" Min dihedral angle = %g.\n", b->mindihedral);
26380  //printf(" Min Edge length = %g.\n", b->minedgelength);
26381  }
26382 
26383  steinerleft = b->steinerleft; // Upperbound of # Steiner points (by -S#).
26384  if (steinerleft > 0) {
26385  // Check if we've already used up the given number of Steiner points.
26386  steinercount = st_segref_count + st_facref_count + st_volref_count;
26387  if (steinercount < steinerleft) {
26388  steinerleft -= steinercount;
26389  } else {
26390  if (!b->quiet) {
26391  printf("\nWarning: ");
26392  printf("The desired number of Steiner points (%d) has reached.\n\n",
26393  b->steinerleft);
26394  }
26395  return; // No more Steiner points.
26396  }
26397  }
26398 
26399  if (useinsertradius) {
26400  if ((b->plc && b->nobisect) || b->refine) { // '-pY' or '-r' option.
26401  makesegmentendpointsmap();
26402  makefacetverticesmap();
26403  }
26404  }
26405 
26406 
26407  encseglist = new arraypool(sizeof(face), 8);
26408  encshlist = new arraypool(sizeof(badface), 8);
26409 
26410 
26411  //if (!b->nobisect) { // if no '-Y' option
26412  if (!b->nobisect || checkconstraints) {
26413  if (b->verbose) {
26414  printf(" Splitting encroached subsegments.\n");
26415  }
26416 
26417  chkencflag = 1; // Only check encroaching subsegments.
26418  steinercount = points->items;
26419 
26420  // Initialize the pool of encroached subsegments.
26421  badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock,
26422  sizeof(void *), 0);
26423 
26424  // Add all segments into the pool.
26425  subsegs->traversalinit();
26426  checkseg.sh = shellfacetraverse(subsegs);
26427  while (checkseg.sh != (shellface *) NULL) {
26428  enqueuesubface(badsubsegs, &checkseg);
26429  checkseg.sh = shellfacetraverse(subsegs);
26430  }
26431 
26432  // Split all encroached segments.
26433  repairencsegs(chkencflag);
26434 
26435  if (b->verbose) {
26436  printf(" Added %ld Steiner points.\n", points->items - steinercount);
26437  }
26438 
26439  if (b->reflevel > 1) { // '-D2' option
26440  if (b->verbose) {
26441  printf(" Splitting encroached subfaces.\n");
26442  }
26443 
26444  chkencflag = 2; // Only check encroaching subfaces.
26445  steinercount = points->items;
26446  bak_segref_count = st_segref_count;
26447  bak_facref_count = st_facref_count;
26448 
26449  // Initialize the pool of encroached subfaces.
26450  badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock,
26451  sizeof(void *), 0);
26452 
26453  // Add all subfaces into the pool.
26454  subfaces->traversalinit();
26455  checksh.sh = shellfacetraverse(subfaces);
26456  while (checksh.sh != (shellface *) NULL) {
26457  enqueuesubface(badsubfacs, &checksh);
26458  checksh.sh = shellfacetraverse(subfaces);
26459  }
26460 
26461  // Split all encroached subfaces.
26462  repairencfacs(chkencflag);
26463 
26464  if (b->verbose) {
26465  printf(" Added %ld (%ld,%ld) Steiner points.\n",
26466  points->items-steinercount, st_segref_count-bak_segref_count,
26467  st_facref_count-bak_facref_count);
26468  }
26469  } // if (b->reflevel > 1)
26470  } // if (!b->nobisect)
26471 
26472  if (b->reflevel > 2) { // '-D3' option (The default option)
26473  if (b->verbose) {
26474  printf(" Splitting bad quality tets.\n");
26475  }
26476 
26477  chkencflag = 4; // Only check tetrahedra.
26478  steinercount = points->items;
26479  bak_segref_count = st_segref_count;
26480  bak_facref_count = st_facref_count;
26481  bak_volref_count = st_volref_count;
26482 
26483  // The cosine value of the min dihedral angle (-qq) for tetrahedra.
26484  cosmindihed = cos(b->mindihedral / 180.0 * PI);
26485 
26486  // Initialize the pool of bad quality tetrahedra.
26487  badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
26488  sizeof(void *), 0);
26489  // Add all tetrahedra (no hull tets) into the pool.
26490  tetrahedrons->traversalinit();
26491  checktet.tet = tetrahedrontraverse();
26492  while (checktet.tet != NULL) {
26493  enqueuetetrahedron(&checktet);
26494  checktet.tet = tetrahedrontraverse();
26495  }
26496 
26497  // Split all bad quality tetrahedra.
26498  repairbadtets(chkencflag);
26499 
26500  if (b->verbose) {
26501  printf(" Added %ld (%ld,%ld,%ld) Steiner points.\n",
26502  points->items - steinercount,
26503  st_segref_count - bak_segref_count,
26504  st_facref_count - bak_facref_count,
26505  st_volref_count - bak_volref_count);
26506  }
26507  } // if (b->reflevel > 2)
26508 
26509  if (b->verbose) {
26510  if (flip23count + flip32count + flip44count > bak_flipcount) {
26511  printf(" Performed %ld flips.\n", flip23count + flip32count +
26512  flip44count - bak_flipcount);
26513  }
26514  }
26515 
26516  if (steinerleft == 0) {
26517  if (!b->quiet) {
26518  printf("\nWarnning: ");
26519  printf("The desired number of Steiner points (%d) is reached.\n\n",
26520  b->steinerleft);
26521  }
26522  }
26523 
26524 
26525  delete encseglist;
26526  delete encshlist;
26527  encseglist = NULL;
26528  encshlist = NULL;
26529 
26530  if (!b->nobisect || checkconstraints) {
26531  totalworkmemory += (badsubsegs->maxitems * badsubsegs->itembytes);
26532  delete badsubsegs;
26533  badsubsegs = NULL;
26534  if (b->reflevel > 1) {
26535  totalworkmemory += (badsubfacs->maxitems * badsubfacs->itembytes);
26536  delete badsubfacs;
26537  badsubfacs = NULL;
26538  }
26539  }
26540  if (b->reflevel > 2) {
26541  totalworkmemory += (badtetrahedrons->maxitems*badtetrahedrons->itembytes);
26542  delete badtetrahedrons;
26543  badtetrahedrons = NULL;
26544  }
26545 }
26546 
26550 
26554 
26556 // //
26557 // lawsonflip3d() A three-dimensional Lawson's algorithm. //
26558 // //
26560 
26561 long tetgenmesh::lawsonflip3d(flipconstraints *fc)
26562 {
26563  triface fliptets[5], neightet, hulltet;
26564  face checksh, casingout;
26565  badface *popface, *bface;
26566  point pd, pe, *pts;
26567  REAL sign, ori;
26568  REAL vol, len3;
26569  long flipcount, totalcount = 0l;
26570  long sliver_peels = 0l;
26571  int t1ver;
26572  int i;
26573 
26574 
26575  while (1) {
26576 
26577  if (b->verbose > 2) {
26578  printf(" Lawson flip %ld faces.\n", flippool->items);
26579  }
26580  flipcount = 0l;
26581 
26582  while (flipstack != (badface *) NULL) {
26583  // Pop a face from the stack.
26584  popface = flipstack;
26585  fliptets[0] = popface->tt;
26586  flipstack = flipstack->nextitem; // The next top item in stack.
26587  flippool->dealloc((void *) popface);
26588 
26589  // Skip it if it is a dead tet (destroyed by previous flips).
26590  if (isdeadtet(fliptets[0])) continue;
26591  // Skip it if it is not the same tet as we saved.
26592  if (!facemarked(fliptets[0])) continue;
26593 
26594  unmarkface(fliptets[0]);
26595 
26596  if (ishulltet(fliptets[0])) continue;
26597 
26598  fsym(fliptets[0], fliptets[1]);
26599  if (ishulltet(fliptets[1])) {
26600  if (nonconvex) {
26601  // Check if 'fliptets[0]' it is a hull sliver.
26602  tspivot(fliptets[0], checksh);
26603  for (i = 0; i < 3; i++) {
26604  if (!isshsubseg(checksh)) {
26605  spivot(checksh, casingout);
26606  //assert(casingout.sh != NULL);
26607  if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
26608  stpivot(casingout, neightet);
26609  if (neightet.tet == fliptets[0].tet) {
26610  // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where
26611  // [e,d,a] and [d,e,b] are hull faces.
26612  edestoppo(neightet, hulltet); // [a,b,e,d]
26613  fsymself(hulltet); // [b,a,e,#]
26614  if (oppo(hulltet) == dummypoint) {
26615  pe = org(neightet);
26616  if ((pointtype(pe) == FREEFACETVERTEX) ||
26617  (pointtype(pe) == FREESEGVERTEX)) {
26618  removevertexbyflips(pe);
26619  }
26620  } else {
26621  eorgoppo(neightet, hulltet); // [b,a,d,e]
26622  fsymself(hulltet); // [a,b,d,#]
26623  if (oppo(hulltet) == dummypoint) {
26624  pd = dest(neightet);
26625  if ((pointtype(pd) == FREEFACETVERTEX) ||
26626  (pointtype(pd) == FREESEGVERTEX)) {
26627  removevertexbyflips(pd);
26628  }
26629  } else {
26630  // Perform a 3-to-2 flip to remove the sliver.
26631  fliptets[0] = neightet; // [e,d,a,b]
26632  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
26633  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
26634  flip32(fliptets, 1, fc);
26635  // Update counters.
26636  flip32count--;
26637  flip22count--;
26638  sliver_peels++;
26639  if (fc->remove_ndelaunay_edge) {
26640  // Update the volume (must be decreased).
26641  //assert(fc->tetprism_vol_sum <= 0);
26642  tetprism_vol_sum += fc->tetprism_vol_sum;
26643  fc->tetprism_vol_sum = 0.0; // Clear it.
26644  }
26645  }
26646  }
26647  break;
26648  } // if (neightet.tet == fliptets[0].tet)
26649  } // if (!isshsubseg(checksh))
26650  senextself(checksh);
26651  } // i
26652  } // if (nonconvex)
26653  continue;
26654  }
26655 
26656  if (checksubfaceflag) {
26657  // Do not flip if it is a subface.
26658  if (issubface(fliptets[0])) continue;
26659  }
26660 
26661  // Test whether the face is locally Delaunay or not.
26662  pts = (point *) fliptets[1].tet;
26663  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
26664 
26665  if (sign < 0) {
26666  // A non-Delaunay face. Try to flip it.
26667  pd = oppo(fliptets[0]);
26668  pe = oppo(fliptets[1]);
26669 
26670  // Use the length of the edge [d,e] as a reference to determine
26671  // a nearly degenerated new tet.
26672  len3 = distance(pd, pe);
26673  len3 = (len3 * len3 * len3);
26674  int round_flag = 0; // [2017-10-20]
26675  // Check the convexity of its three edges. Stop checking either a
26676  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
26677  // encountered, and 'fliptet' represents that edge.
26678  for (i = 0; i < 3; i++) {
26679  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
26680  if (ori > 0) {
26681  // Avoid creating a nearly degenerated new tet at boundary.
26682  // Re-use fliptets[2], fliptets[3];
26683  esym(fliptets[0], fliptets[2]);
26684  esym(fliptets[1], fliptets[3]);
26685  if (issubface(fliptets[2]) || issubface(fliptets[3])) {
26686  vol = orient3dfast(org(fliptets[0]), dest(fliptets[0]), pd, pe);
26687  if ((fabs(vol) / len3) < b->epsilon) {
26688  ori = 0.0; // Do rounding.
26689  round_flag = 1; // [2017-10-20]
26690  }
26691  }
26692  } // Rounding check
26693  if (ori <= 0) break;
26694  enextself(fliptets[0]);
26695  eprevself(fliptets[1]);
26696  }
26697 
26698  if (ori > 0) {
26699  // A 2-to-3 flip is found.
26700  // [0] [a,b,c,d],
26701  // [1] [b,a,c,e]. no dummypoint.
26702  flip23(fliptets, 0, fc);
26703  flipcount++;
26704  if (fc->remove_ndelaunay_edge) {
26705  // Update the volume (must be decreased).
26706  //assert(fc->tetprism_vol_sum <= 0);
26707  tetprism_vol_sum += fc->tetprism_vol_sum;
26708  fc->tetprism_vol_sum = 0.0; // Clear it.
26709  }
26710  continue;
26711  } else { // ori <= 0
26712  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
26713  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
26714  if (checksubsegflag) {
26715  // Do not flip if it is a segment.
26716  if (issubseg(fliptets[0])) continue;
26717  }
26718  // Check if there are three or four tets sharing at this edge.
26719  esymself(fliptets[0]); // [b,a,d,c]
26720  for (i = 0; i < 3; i++) {
26721  fnext(fliptets[i], fliptets[i+1]);
26722  }
26723  if (fliptets[3].tet == fliptets[0].tet) {
26724  // A 3-to-2 flip is found. (No hull tet.)
26725  flip32(fliptets, 0, fc);
26726  flipcount++;
26727  if (fc->remove_ndelaunay_edge) {
26728  // Update the volume (must be decreased).
26729  //assert(fc->tetprism_vol_sum <= 0);
26730  tetprism_vol_sum += fc->tetprism_vol_sum;
26731  fc->tetprism_vol_sum = 0.0; // Clear it.
26732  }
26733  continue;
26734  } else {
26735  // There are more than 3 tets at this edge.
26736  fnext(fliptets[3], fliptets[4]);
26737  if (fliptets[4].tet == fliptets[0].tet) {
26738  // There are exactly 4 tets at this edge.
26739  if (round_flag == 1) {
26740  continue; // [2017-10-20]
26741  }
26742  if (nonconvex) {
26743  if (apex(fliptets[3]) == dummypoint) {
26744  // This edge is locally non-convex on the hull.
26745  // It can be removed by a 4-to-4 flip.
26746  ori = 0;
26747  }
26748  } // if (nonconvex)
26749  if (ori == 0) {
26750  // A 4-to-4 flip is found. (Two hull tets may be involved.)
26751  // Current tets in 'fliptets':
26752  // [0] [b,a,d,c] (d may be newpt)
26753  // [1] [b,a,c,e]
26754  // [2] [b,a,e,f] (f may be dummypoint)
26755  // [3] [b,a,f,d]
26756  esymself(fliptets[0]); // [a,b,c,d]
26757  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
26758  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
26759  // It will be removed by the followed 3-to-2 flip.
26760  flip23(fliptets, 0, fc); // No hull tet.
26761  fnext(fliptets[3], fliptets[1]);
26762  fnext(fliptets[1], fliptets[2]);
26763  // Current tets in 'fliptets':
26764  // [0] [...]
26765  // [1] [b,a,d,e] (degenerated, d may be new point).
26766  // [2] [b,a,e,f] (f may be dummypoint)
26767  // [3] [b,a,f,d]
26768  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
26769  // Hull tets may be involved (f may be dummypoint).
26770  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
26771  flipcount++;
26772  flip23count--;
26773  flip32count--;
26774  flip44count++;
26775  if (fc->remove_ndelaunay_edge) {
26776  // Update the volume (must be decreased).
26777  //assert(fc->tetprism_vol_sum <= 0);
26778  tetprism_vol_sum += fc->tetprism_vol_sum;
26779  fc->tetprism_vol_sum = 0.0; // Clear it.
26780  }
26782  //if (checkmesh(0) > 0) {
26783  // assert(0);
26784  //}
26785  continue;
26786  } // if (ori == 0)
26787  }
26788  }
26789  } // if (ori <= 0)
26790 
26791  // This non-Delaunay face is unflippable. Save it.
26792  unflipqueue->newindex((void **) &bface);
26793  bface->tt = fliptets[0];
26794  bface->forg = org(fliptets[0]);
26795  bface->fdest = dest(fliptets[0]);
26796  bface->fapex = apex(fliptets[0]);
26797  } // if (sign < 0)
26798  } // while (flipstack)
26799 
26800  if (b->verbose > 2) {
26801  if (flipcount > 0) {
26802  printf(" Performed %ld flips.\n", flipcount);
26803  }
26804  }
26805  // Accumulate the counter of flips.
26806  totalcount += flipcount;
26807 
26808  // Return if no unflippable faces left.
26809  if (unflipqueue->objects == 0l) break;
26810  // Return if no flip has been performed.
26811  if (flipcount == 0l) break;
26812 
26813  // Try to flip the unflippable faces.
26814  for (i = 0; i < unflipqueue->objects; i++) {
26815  bface = (badface *) fastlookup(unflipqueue, i);
26816  if (!isdeadtet(bface->tt) &&
26817  (org(bface->tt) == bface->forg) &&
26818  (dest(bface->tt) == bface->fdest) &&
26819  (apex(bface->tt) == bface->fapex)) {
26820  flippush(flipstack, &(bface->tt));
26821  }
26822  }
26823  unflipqueue->restart();
26824 
26825  } // while (1)
26826 
26827  if (b->verbose > 2) {
26828  if (totalcount > 0) {
26829  printf(" Performed %ld flips.\n", totalcount);
26830  }
26831  if (sliver_peels > 0) {
26832  printf(" Removed %ld hull slivers.\n", sliver_peels);
26833  }
26834  if (unflipqueue->objects > 0l) {
26835  printf(" %ld unflippable edges remained.\n", unflipqueue->objects);
26836  }
26837  }
26838 
26839  return totalcount + sliver_peels;
26840 }
26841 
26843 // //
26844 // recoverdelaunay() Recovery the locally Delaunay property. //
26845 // //
26847 
26848 void tetgenmesh::recoverdelaunay()
26849 {
26850  arraypool *flipqueue, *nextflipqueue, *swapqueue;
26851  triface tetloop, neightet, *parytet;
26852  badface *bface, *parybface;
26853  point *ppt;
26854  flipconstraints fc;
26855  int i, j;
26856 
26857  if (!b->quiet) {
26858  printf("Recovering Delaunayness...\n");
26859  }
26860 
26861  tetprism_vol_sum = 0.0; // Initialize it.
26862 
26863  // Put all interior faces of the mesh into 'flipstack'.
26864  tetrahedrons->traversalinit();
26865  tetloop.tet = tetrahedrontraverse();
26866  while (tetloop.tet != NULL) {
26867  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
26868  decode(tetloop.tet[tetloop.ver], neightet);
26869  if (!facemarked(neightet)) {
26870  flippush(flipstack, &tetloop);
26871  }
26872  }
26873  ppt = (point *) &(tetloop.tet[4]);
26874  tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
26875  tetloop.tet = tetrahedrontraverse();
26876  }
26877 
26878  // Calulate a relatively lower bound for small improvement.
26879  // Used to avoid rounding error in volume calculation.
26880  fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
26881 
26882  if (b->verbose) {
26883  printf(" Initial obj = %.17g\n", tetprism_vol_sum);
26884  }
26885 
26886  if (b->verbose > 1) {
26887  printf(" Recover Delaunay [Lawson] : %ld\n", flippool->items);
26888  }
26889 
26890  // First only use the basic Lawson's flip.
26891  fc.remove_ndelaunay_edge = 1;
26892  fc.enqflag = 2;
26893 
26894  lawsonflip3d(&fc);
26895 
26896  if (b->verbose > 1) {
26897  printf(" obj (after Lawson) = %.17g\n", tetprism_vol_sum);
26898  }
26899 
26900  if (unflipqueue->objects == 0l) {
26901  return; // The mesh is Delaunay.
26902  }
26903 
26904  fc.unflip = 1; // Unflip if the edge is not flipped.
26905  fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
26906  fc.enqflag = 0;
26907 
26908  autofliplinklevel = 1; // Init level.
26909  b->fliplinklevel = -1; // No fixed level.
26910 
26911  // For efficiency reason, we limit the maximium size of the edge star.
26912  int bakmaxflipstarsize = b->flipstarsize;
26913  b->flipstarsize = 10; // default
26914 
26915  flipqueue = new arraypool(sizeof(badface), 10);
26916  nextflipqueue = new arraypool(sizeof(badface), 10);
26917 
26918  // Swap the two flip queues.
26919  swapqueue = flipqueue;
26920  flipqueue = unflipqueue;
26921  unflipqueue = swapqueue;
26922 
26923  while (flipqueue->objects > 0l) {
26924 
26925  if (b->verbose > 1) {
26926  printf(" Recover Delaunay [level = %2d] #: %ld.\n",
26927  autofliplinklevel, flipqueue->objects);
26928  }
26929 
26930  for (i = 0; i < flipqueue->objects; i++) {
26931  bface = (badface *) fastlookup(flipqueue, i);
26932  if (getedge(bface->forg, bface->fdest, &bface->tt)) {
26933  if (removeedgebyflips(&(bface->tt), &fc) == 2) {
26934  tetprism_vol_sum += fc.tetprism_vol_sum;
26935  fc.tetprism_vol_sum = 0.0; // Clear it.
26936  // Queue new faces for flips.
26937  for (j = 0; j < cavetetlist->objects; j++) {
26938  parytet = (triface *) fastlookup(cavetetlist, j);
26939  // A queued new tet may be dead.
26940  if (!isdeadtet(*parytet)) {
26941  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
26942  // Avoid queue a face twice.
26943  decode(parytet->tet[parytet->ver], neightet);
26944  if (!facemarked(neightet)) {
26945  flippush(flipstack, parytet);
26946  }
26947  } // parytet->ver
26948  }
26949  } // j
26950  cavetetlist->restart();
26951  // Remove locally non-Delaunay faces. New non-Delaunay edges
26952  // may be found. They are saved in 'unflipqueue'.
26953  fc.enqflag = 2;
26954  lawsonflip3d(&fc);
26955  fc.enqflag = 0;
26956  // There may be unflipable faces. Add them in flipqueue.
26957  for (j = 0; j < unflipqueue->objects; j++) {
26958  bface = (badface *) fastlookup(unflipqueue, j);
26959  flipqueue->newindex((void **) &parybface);
26960  *parybface = *bface;
26961  }
26962  unflipqueue->restart();
26963  } else {
26964  // Unable to remove this edge. Save it.
26965  nextflipqueue->newindex((void **) &parybface);
26966  *parybface = *bface;
26967  // Normally, it should be zero.
26968  //assert(fc.tetprism_vol_sum == 0.0);
26969  // However, due to rounding errors, a tiny value may appear.
26970  fc.tetprism_vol_sum = 0.0;
26971  }
26972  }
26973  } // i
26974 
26975  if (b->verbose > 1) {
26976  printf(" obj (after level %d) = %.17g.\n", autofliplinklevel,
26977  tetprism_vol_sum);
26978  }
26979  flipqueue->restart();
26980 
26981  // Swap the two flip queues.
26982  swapqueue = flipqueue;
26983  flipqueue = nextflipqueue;
26984  nextflipqueue = swapqueue;
26985 
26986  if (flipqueue->objects > 0l) {
26987  // default 'b->delmaxfliplevel' is 1.
26988  if (autofliplinklevel >= b->delmaxfliplevel) {
26989  // For efficiency reason, we do not search too far.
26990  break;
26991  }
26992  autofliplinklevel+=b->fliplinklevelinc;
26993  }
26994  } // while (flipqueue->objects > 0l)
26995 
26996  if (flipqueue->objects > 0l) {
26997  if (b->verbose > 1) {
26998  printf(" %ld non-Delaunay edges remained.\n", flipqueue->objects);
26999  }
27000  }
27001 
27002  if (b->verbose) {
27003  printf(" Final obj = %.17g\n", tetprism_vol_sum);
27004  }
27005 
27006  b->flipstarsize = bakmaxflipstarsize;
27007  delete flipqueue;
27008  delete nextflipqueue;
27009 }
27010 
27012 // //
27013 // gettetrahedron() Get a tetrahedron which have the given vertices. //
27014 // //
27016 
27017 int tetgenmesh::gettetrahedron(point pa, point pb, point pc, point pd,
27018  triface *searchtet)
27019 {
27020  triface spintet;
27021  int t1ver;
27022 
27023  if (getedge(pa, pb, searchtet)) {
27024  spintet = *searchtet;
27025  while (1) {
27026  if (apex(spintet) == pc) {
27027  *searchtet = spintet;
27028  break;
27029  }
27030  fnextself(spintet);
27031  if (spintet.tet == searchtet->tet) break;
27032  }
27033  if (apex(*searchtet) == pc) {
27034  if (oppo(*searchtet) == pd) {
27035  return 1;
27036  } else {
27037  fsymself(*searchtet);
27038  if (oppo(*searchtet) == pd) {
27039  return 1;
27040  }
27041  }
27042  }
27043  }
27044 
27045  return 0;
27046 }
27047 
27049 // //
27050 // improvequalitybyflips() Improve the mesh quality by flips. //
27051 // //
27053 
27054 long tetgenmesh::improvequalitybyflips()
27055 {
27056  arraypool *flipqueue, *nextflipqueue, *swapqueue;
27057  badface *bface, *parybface;
27058  triface *parytet;
27059  point *ppt;
27060  flipconstraints fc;
27061  REAL *cosdd, ncosdd[6], maxdd;
27062  long totalremcount, remcount;
27063  int remflag;
27064  int n, i, j, k;
27065 
27066  //assert(unflipqueue->objects > 0l);
27067  flipqueue = new arraypool(sizeof(badface), 10);
27068  nextflipqueue = new arraypool(sizeof(badface), 10);
27069 
27070  // Backup flip edge options.
27071  int bakautofliplinklevel = autofliplinklevel;
27072  int bakfliplinklevel = b->fliplinklevel;
27073  int bakmaxflipstarsize = b->flipstarsize;
27074 
27075  // Set flip edge options.
27076  autofliplinklevel = 1;
27077  b->fliplinklevel = -1;
27078  b->flipstarsize = 10; // b->optmaxflipstarsize;
27079 
27080  fc.remove_large_angle = 1;
27081  fc.unflip = 1;
27082  fc.collectnewtets = 1;
27083  fc.checkflipeligibility = 1;
27084 
27085  totalremcount = 0l;
27086 
27087  // Swap the two flip queues.
27088  swapqueue = flipqueue;
27089  flipqueue = unflipqueue;
27090  unflipqueue = swapqueue;
27091 
27092  while (flipqueue->objects > 0l) {
27093 
27094  remcount = 0l;
27095 
27096  while (flipqueue->objects > 0l) {
27097  if (b->verbose > 1) {
27098  printf(" Improving mesh qualiy by flips [%d]#: %ld.\n",
27099  autofliplinklevel, flipqueue->objects);
27100  }
27101 
27102  for (k = 0; k < flipqueue->objects; k++) {
27103  bface = (badface *) fastlookup(flipqueue, k);
27104  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
27105  bface->foppo, &bface->tt)) {
27106  //assert(!ishulltet(bface->tt));
27107  // There are bad dihedral angles in this tet.
27108  if (bface->tt.ver != 11) {
27109  // The dihedral angles are permuted.
27110  // Here we simply re-compute them. Slow!!.
27111  ppt = (point *) & (bface->tt.tet[4]);
27112  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27113  &bface->key, NULL);
27114  bface->forg = ppt[0];
27115  bface->fdest = ppt[1];
27116  bface->fapex = ppt[2];
27117  bface->foppo = ppt[3];
27118  bface->tt.ver = 11;
27119  }
27120  if (bface->key == 0) {
27121  // Re-comput the quality values. Due to smoothing operations.
27122  ppt = (point *) & (bface->tt.tet[4]);
27123  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27124  &bface->key, NULL);
27125  }
27126  cosdd = bface->cent;
27127  remflag = 0;
27128  for (i = 0; (i < 6) && !remflag; i++) {
27129  if (cosdd[i] < cosmaxdihed) {
27130  // Found a large dihedral angle.
27131  bface->tt.ver = edge2ver[i]; // Go to the edge.
27132  fc.cosdihed_in = cosdd[i];
27133  fc.cosdihed_out = 0.0; // 90 degree.
27134  n = removeedgebyflips(&(bface->tt), &fc);
27135  if (n == 2) {
27136  // Edge is flipped.
27137  remflag = 1;
27138  if (fc.cosdihed_out < cosmaxdihed) {
27139  // Queue new bad tets for further improvements.
27140  for (j = 0; j < cavetetlist->objects; j++) {
27141  parytet = (triface *) fastlookup(cavetetlist, j);
27142  if (!isdeadtet(*parytet)) {
27143  ppt = (point *) & (parytet->tet[4]);
27144  // Do not test a hull tet.
27145  if (ppt[3] != dummypoint) {
27146  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd,
27147  &maxdd, NULL);
27148  if (maxdd < cosmaxdihed) {
27149  // There are bad dihedral angles in this tet.
27150  nextflipqueue->newindex((void **) &parybface);
27151  parybface->tt.tet = parytet->tet;
27152  parybface->tt.ver = 11;
27153  parybface->forg = ppt[0];
27154  parybface->fdest = ppt[1];
27155  parybface->fapex = ppt[2];
27156  parybface->foppo = ppt[3];
27157  parybface->key = maxdd;
27158  for (n = 0; n < 6; n++) {
27159  parybface->cent[n] = ncosdd[n];
27160  }
27161  }
27162  } // if (ppt[3] != dummypoint)
27163  }
27164  } // j
27165  } // if (fc.cosdihed_out < cosmaxdihed)
27166  cavetetlist->restart();
27167  remcount++;
27168  }
27169  }
27170  } // i
27171  if (!remflag) {
27172  // An unremoved bad tet. Queue it again.
27173  unflipqueue->newindex((void **) &parybface);
27174  *parybface = *bface;
27175  }
27176  } // if (gettetrahedron(...))
27177  } // k
27178 
27179  flipqueue->restart();
27180 
27181  // Swap the two flip queues.
27182  swapqueue = flipqueue;
27183  flipqueue = nextflipqueue;
27184  nextflipqueue = swapqueue;
27185  } // while (flipqueues->objects > 0)
27186 
27187  if (b->verbose > 1) {
27188  printf(" Removed %ld bad tets.\n", remcount);
27189  }
27190  totalremcount += remcount;
27191 
27192  if (unflipqueue->objects > 0l) {
27193  //if (autofliplinklevel >= b->optmaxfliplevel) {
27194  if (autofliplinklevel >= b->optlevel) {
27195  break;
27196  }
27197  autofliplinklevel+=b->fliplinklevelinc;
27198  //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
27199  }
27200 
27201  // Swap the two flip queues.
27202  swapqueue = flipqueue;
27203  flipqueue = unflipqueue;
27204  unflipqueue = swapqueue;
27205  } // while (flipqueues->objects > 0)
27206 
27207  // Restore original flip edge options.
27208  autofliplinklevel = bakautofliplinklevel;
27209  b->fliplinklevel = bakfliplinklevel;
27210  b->flipstarsize = bakmaxflipstarsize;
27211 
27212  delete flipqueue;
27213  delete nextflipqueue;
27214 
27215  return totalremcount;
27216 }
27217 
27219 // //
27220 // smoothpoint() Moving a vertex to improve the mesh quality. //
27221 // //
27222 // 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point. //
27223 // It may be not a vertex of the mesh. //
27224 // //
27225 // This routine tries to move 'p' inside its star until a selected objective //
27226 // function over all tetrahedra in the star is improved. The function may be //
27227 // the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
27228 // simply the volume of the tetrahedra. //
27229 // //
27230 // 'linkfacelist' contains the list of link faces of 'p'. Since a link face //
27231 // has two orientations, ccw or cw, with respect to 'p'. 'ccw' indicates //
27232 // the orientation is ccw (1) or not (0). //
27233 // //
27234 // 'opm' is a structure contains the parameters of the objective function. //
27235 // It is needed by the evaluation of the function value. //
27236 // //
27237 // The return value indicates weather the point is smoothed or not. //
27238 // //
27239 // ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
27240 // no face has 'dummypoint' as its vertex. //
27241 // //
27243 
27244 int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
27245  optparameters *opm)
27246 {
27247  triface *parytet, *parytet1, swaptet;
27248  point pa, pb, pc;
27249  REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
27250  REAL oldval, minval = 0.0, val;
27251  REAL maxcosd; // oldang, newang;
27252  REAL ori, diff;
27253  int numdirs, iter;
27254  int i, j, k;
27255 
27256  // Decide the number of moving directions.
27257  numdirs = (int) linkfacelist->objects;
27258  if (numdirs > opm->numofsearchdirs) {
27259  numdirs = opm->numofsearchdirs; // Maximum search directions.
27260  }
27261 
27262  // Set the initial value.
27263  opm->imprval = opm->initval;
27264  iter = 0;
27265 
27266  for (i = 0; i < 3; i++) {
27267  bestpt[i] = startpt[i] = smtpt[i];
27268  }
27269 
27270  // Iterate until the obj function is not improved.
27271  while (1) {
27272 
27273  // Find the best next location.
27274  oldval = opm->imprval;
27275 
27276  for (i = 0; i < numdirs; i++) {
27277  // Randomly pick a link face (0 <= k <= objects - i - 1).
27278  k = (int) randomnation(linkfacelist->objects - i);
27279  parytet = (triface *) fastlookup(linkfacelist, k);
27280  // Calculate a new position from 'p' to the center of this face.
27281  pa = org(*parytet);
27282  pb = dest(*parytet);
27283  pc = apex(*parytet);
27284  for (j = 0; j < 3; j++) {
27285  fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
27286  }
27287  for (j = 0; j < 3; j++) {
27288  nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]);
27289  }
27290  // Calculate the largest minimum function value for the new location.
27291  for (j = 0; j < linkfacelist->objects; j++) {
27292  parytet = (triface *) fastlookup(linkfacelist, j);
27293  if (ccw) {
27294  pa = org(*parytet);
27295  pb = dest(*parytet);
27296  } else {
27297  pb = org(*parytet);
27298  pa = dest(*parytet);
27299  }
27300  pc = apex(*parytet);
27301  ori = orient3d(pa, pb, pc, nextpt);
27302  if (ori < 0.0) {
27303  // Calcuate the objective function value.
27304  if (opm->max_min_volume) {
27305  //val = -ori;
27306  val = - orient3dfast(pa, pb, pc, nextpt);
27307  } else if (opm->min_max_aspectratio) {
27308  val = 1.0 / tetaspectratio(pa, pb, pc, nextpt);
27309  } else if (opm->min_max_dihedangle) {
27310  tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
27311  if (maxcosd < -1) maxcosd = -1.0; // Rounding.
27312  val = maxcosd + 1.0; // Make it be positive.
27313  } else {
27314  // Unknown objective function.
27315  val = 0.0;
27316  }
27317  } else { // ori >= 0.0;
27318  // An invalid new tet.
27319  // This may happen if the mesh contains inverted elements.
27320  if (opm->max_min_volume) {
27321  //val = -ori;
27322  val = - orient3dfast(pa, pb, pc, nextpt);
27323  } else {
27324  // Discard this point.
27325  break; // j
27326  }
27327  } // if (ori >= 0.0)
27328  // Stop looping when the object value is not improved.
27329  if (val <= opm->imprval) {
27330  break; // j
27331  } else {
27332  // Remember the smallest improved value.
27333  if (j == 0) {
27334  minval = val;
27335  } else {
27336  minval = (val < minval) ? val : minval;
27337  }
27338  }
27339  } // j
27340  if (j == linkfacelist->objects) {
27341  // The function value has been improved.
27342  opm->imprval = minval;
27343  // Save the new location of the point.
27344  for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
27345  }
27346  // Swap k-th and (object-i-1)-th entries.
27347  j = linkfacelist->objects - i - 1;
27348  parytet = (triface *) fastlookup(linkfacelist, k);
27349  parytet1 = (triface *) fastlookup(linkfacelist, j);
27350  swaptet = *parytet1;
27351  *parytet1 = *parytet;
27352  *parytet = swaptet;
27353  } // i
27354 
27355  diff = opm->imprval - oldval;
27356  if (diff > 0.0) {
27357  // Is the function value improved effectively?
27358  if (opm->max_min_volume) {
27359  //if ((diff / oldval) < b->epsilon) diff = 0.0;
27360  } else if (opm->min_max_aspectratio) {
27361  if ((diff / oldval) < 1e-3) diff = 0.0;
27362  } else if (opm->min_max_dihedangle) {
27363  //oldang = acos(oldval - 1.0);
27364  //newang = acos(opm->imprval - 1.0);
27365  //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
27366  } else {
27367  // Unknown objective function.
27368  terminatetetgen(this, 2);
27369  }
27370  }
27371 
27372  if (diff > 0.0) {
27373  // Yes, move p to the new location and continue.
27374  for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
27375  iter++;
27376  if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
27377  // Maximum smoothing iterations reached.
27378  break;
27379  }
27380  } else {
27381  break;
27382  }
27383 
27384  } // while (1)
27385 
27386  if (iter > 0) {
27387  // The point has been smoothed.
27388  opm->smthiter = iter; // Remember the number of iterations.
27389  // The point has been smoothed. Update it to its new position.
27390  for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
27391  }
27392 
27393  return iter;
27394 }
27395 
27396 
27398 // //
27399 // improvequalitysmoothing() Improve mesh quality by smoothing. //
27400 // //
27402 
27403 long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
27404 {
27405  arraypool *flipqueue, *swapqueue;
27406  triface *parytet;
27407  badface *bface, *parybface;
27408  point *ppt;
27409  long totalsmtcount, smtcount;
27410  int smtflag;
27411  int iter, i, j, k;
27412 
27413  //assert(unflipqueue->objects > 0l);
27414  flipqueue = new arraypool(sizeof(badface), 10);
27415 
27416  // Swap the two flip queues.
27417  swapqueue = flipqueue;
27418  flipqueue = unflipqueue;
27419  unflipqueue = swapqueue;
27420 
27421  totalsmtcount = 0l;
27422  iter = 0;
27423 
27424  while (flipqueue->objects > 0l) {
27425 
27426  smtcount = 0l;
27427 
27428  if (b->verbose > 1) {
27429  printf(" Improving mesh quality by smoothing [%d]#: %ld.\n",
27430  iter, flipqueue->objects);
27431  }
27432 
27433  for (k = 0; k < flipqueue->objects; k++) {
27434  bface = (badface *) fastlookup(flipqueue, k);
27435  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
27436  bface->foppo, &bface->tt)) {
27437  // Operate on it if it is not in 'unflipqueue'.
27438  if (!marktested(bface->tt)) {
27439  // Here we simply re-compute the quality. Since other smoothing
27440  // operation may have moved the vertices of this tet.
27441  ppt = (point *) & (bface->tt.tet[4]);
27442  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27443  &bface->key, NULL);
27444  if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
27445  // It is a sliver. Try to smooth its vertices.
27446  smtflag = 0;
27447  opm->initval = bface->key + 1.0;
27448  for (i = 0; (i < 4) && !smtflag; i++) {
27449  if (pointtype(ppt[i]) == FREEVOLVERTEX) {
27450  getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
27451  opm->searchstep = 0.001; // Search step size
27452  smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
27453  if (smtflag) {
27454  while (opm->smthiter == opm->maxiter) {
27455  opm->searchstep *= 10.0; // Increase the step size.
27456  opm->initval = opm->imprval;
27457  opm->smthiter = 0; // reset
27458  smoothpoint(ppt[i], cavetetlist, 1, opm);
27459  }
27460  // This tet is modifed.
27461  smtcount++;
27462  if ((opm->imprval - 1.0) < cossmtdihed) {
27463  // There are slivers in new tets. Queue them.
27464  for (j = 0; j < cavetetlist->objects; j++) {
27465  parytet = (triface *) fastlookup(cavetetlist, j);
27466  // Operate it if it is not in 'unflipqueue'.
27467  if (!marktested(*parytet)) {
27468  // Evaluate its quality.
27469  // Re-use ppt, bface->key, bface->cent.
27470  ppt = (point *) & (parytet->tet[4]);
27471  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3],
27472  bface->cent, &bface->key, NULL);
27473  if (bface->key < cossmtdihed) {
27474  // A new sliver. Queue it.
27475  marktest(*parytet); // It is in unflipqueue.
27476  unflipqueue->newindex((void **) &parybface);
27477  parybface->tt = *parytet;
27478  parybface->forg = ppt[0];
27479  parybface->fdest = ppt[1];
27480  parybface->fapex = ppt[2];
27481  parybface->foppo = ppt[3];
27482  parybface->tt.ver = 11;
27483  parybface->key = 0.0;
27484  }
27485  }
27486  } // j
27487  } // if ((opm->imprval - 1.0) < cossmtdihed)
27488  } // if (smtflag)
27489  cavetetlist->restart();
27490  } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
27491  } // i
27492  if (!smtflag) {
27493  // Didn't smooth. Queue it again.
27494  marktest(bface->tt); // It is in unflipqueue.
27495  unflipqueue->newindex((void **) &parybface);
27496  parybface->tt = bface->tt;
27497  parybface->forg = ppt[0];
27498  parybface->fdest = ppt[1];
27499  parybface->fapex = ppt[2];
27500  parybface->foppo = ppt[3];
27501  parybface->tt.ver = 11;
27502  parybface->key = 0.0;
27503  }
27504  } // if (maxdd < cosslidihed)
27505  } // if (!marktested(...))
27506  } // if (gettetrahedron(...))
27507  } // k
27508 
27509  flipqueue->restart();
27510 
27511  // Unmark the tets in unflipqueue.
27512  for (i = 0; i < unflipqueue->objects; i++) {
27513  bface = (badface *) fastlookup(unflipqueue, i);
27514  unmarktest(bface->tt);
27515  }
27516 
27517  if (b->verbose > 1) {
27518  printf(" Smooth %ld points.\n", smtcount);
27519  }
27520  totalsmtcount += smtcount;
27521 
27522  if (smtcount == 0l) {
27523  // No point has been smoothed.
27524  break;
27525  } else {
27526  iter++;
27527  if (iter == 2) { //if (iter >= b->optpasses) {
27528  break;
27529  }
27530  }
27531 
27532  // Swap the two flip queues.
27533  swapqueue = flipqueue;
27534  flipqueue = unflipqueue;
27535  unflipqueue = swapqueue;
27536  } // while
27537 
27538  delete flipqueue;
27539 
27540  return totalsmtcount;
27541 }
27542 
27544 // //
27545 // splitsliver() Split a sliver. //
27546 // //
27548 
27549 int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
27550 {
27551  triface *abtets;
27552  triface searchtet, spintet, *parytet;
27553  point pa, pb, steinerpt;
27554  optparameters opm;
27555  insertvertexflags ivf;
27556  REAL smtpt[3], midpt[3];
27557  int success;
27558  int t1ver;
27559  int n, i;
27560 
27561  // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle.
27562  // Go to the opposite edge [a,b].
27563  edestoppo(*slitet, searchtet); // [a,b,c,d].
27564 
27565  // Do not split a segment.
27566  if (issubseg(searchtet)) {
27567  return 0;
27568  }
27569 
27570  // Count the number of tets shared at [a,b].
27571  // Do not split it if it is a hull edge.
27572  spintet = searchtet;
27573  n = 0;
27574  while (1) {
27575  if (ishulltet(spintet)) break;
27576  n++;
27577  fnextself(spintet);
27578  if (spintet.tet == searchtet.tet) break;
27579  }
27580  if (ishulltet(spintet)) {
27581  return 0; // It is a hull edge.
27582  }
27583 
27584  // Get all tets at edge [a,b].
27585  abtets = new triface[n];
27586  spintet = searchtet;
27587  for (i = 0; i < n; i++) {
27588  abtets[i] = spintet;
27589  fnextself(spintet);
27590  }
27591 
27592  // Initialize the list of 2n boundary faces.
27593  for (i = 0; i < n; i++) {
27594  eprev(abtets[i], searchtet);
27595  esymself(searchtet); // [a,p_i,p_i+1].
27596  cavetetlist->newindex((void **) &parytet);
27597  *parytet = searchtet;
27598  enext(abtets[i], searchtet);
27599  esymself(searchtet); // [p_i,b,p_i+1].
27600  cavetetlist->newindex((void **) &parytet);
27601  *parytet = searchtet;
27602  }
27603 
27604  // Init the Steiner point at the midpoint of edge [a,b].
27605  pa = org(abtets[0]);
27606  pb = dest(abtets[0]);
27607  for (i = 0; i < 3; i++) {
27608  smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
27609  }
27610 
27611  // Point smooth options.
27612  opm.min_max_dihedangle = 1;
27613  opm.initval = cosd + 1.0; // Initial volume is zero.
27614  opm.numofsearchdirs = 20;
27615  opm.searchstep = 0.001;
27616  opm.maxiter = 100; // Limit the maximum iterations.
27617 
27618  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
27619 
27620  if (success) {
27621  while (opm.smthiter == opm.maxiter) {
27622  // It was relocated and the prescribed maximum iteration reached.
27623  // Try to increase the search stepsize.
27624  opm.searchstep *= 10.0;
27625  //opm.maxiter = 100; // Limit the maximum iterations.
27626  opm.initval = opm.imprval;
27627  opm.smthiter = 0; // Init.
27628  smoothpoint(smtpt, cavetetlist, 1, &opm);
27629  }
27630  } // if (success)
27631 
27632  cavetetlist->restart();
27633 
27634  if (!success) {
27635  delete [] abtets;
27636  return 0;
27637  }
27638 
27639 
27640  // Insert the Steiner point.
27641  makepoint(&steinerpt, FREEVOLVERTEX);
27642  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
27643 
27644  // Insert the created Steiner point.
27645  for (i = 0; i < n; i++) {
27646  infect(abtets[i]);
27647  caveoldtetlist->newindex((void **) &parytet);
27648  *parytet = abtets[i];
27649  }
27650 
27651  searchtet = abtets[0]; // No need point location.
27652  if (b->metric) {
27653  locate(steinerpt, &searchtet); // For size interpolation.
27654  }
27655 
27656  delete [] abtets;
27657 
27658  ivf.iloc = (int) INSTAR;
27659  ivf.chkencflag = chkencflag;
27660  ivf.assignmeshsize = b->metric;
27661 
27662 
27663  if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
27664  // The vertex has been inserted.
27665  st_volref_count++;
27666  if (steinerleft > 0) steinerleft--;
27667  return 1;
27668  } else {
27669  // The Steiner point is too close to an existing vertex. Reject it.
27670  pointdealloc(steinerpt);
27671  return 0;
27672  }
27673 }
27674 
27676 // //
27677 // removeslivers() Remove slivers by adding Steiner points. //
27678 // //
27680 
27681 long tetgenmesh::removeslivers(int chkencflag)
27682 {
27683  arraypool *flipqueue, *swapqueue;
27684  badface *bface, *parybface;
27685  triface slitet, *parytet;
27686  point *ppt;
27687  REAL cosdd[6], maxcosd;
27688  long totalsptcount, sptcount;
27689  int iter, i, j, k;
27690 
27691  //assert(unflipqueue->objects > 0l);
27692  flipqueue = new arraypool(sizeof(badface), 10);
27693 
27694  // Swap the two flip queues.
27695  swapqueue = flipqueue;
27696  flipqueue = unflipqueue;
27697  unflipqueue = swapqueue;
27698 
27699  totalsptcount = 0l;
27700  iter = 0;
27701 
27702  while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
27703 
27704  sptcount = 0l;
27705 
27706  if (b->verbose > 1) {
27707  printf(" Splitting bad quality tets [%d]#: %ld.\n",
27708  iter, flipqueue->objects);
27709  }
27710 
27711  for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {
27712  bface = (badface *) fastlookup(flipqueue, k);
27713  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
27714  bface->foppo, &bface->tt)) {
27715  if ((bface->key == 0) || (bface->tt.ver != 11)) {
27716  // Here we need to re-compute the quality. Since other smoothing
27717  // operation may have moved the vertices of this tet.
27718  ppt = (point *) & (bface->tt.tet[4]);
27719  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27720  &bface->key, NULL);
27721  }
27722  if (bface->key < cosslidihed) {
27723  // It is a sliver. Try to split it.
27724  slitet.tet = bface->tt.tet;
27725  //cosdd = bface->cent;
27726  for (j = 0; j < 6; j++) {
27727  if (bface->cent[j] < cosslidihed) {
27728  // Found a large dihedral angle.
27729  slitet.ver = edge2ver[j]; // Go to the edge.
27730  if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
27731  sptcount++;
27732  break;
27733  }
27734  }
27735  } // j
27736  if (j < 6) {
27737  // A sliver is split. Queue new slivers.
27738  badtetrahedrons->traversalinit();
27739  parytet = (triface *) badtetrahedrons->traverse();
27740  while (parytet != NULL) {
27741  unmarktest2(*parytet);
27742  ppt = (point *) & (parytet->tet[4]);
27743  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd,
27744  &maxcosd, NULL);
27745  if (maxcosd < cosslidihed) {
27746  // A new sliver. Queue it.
27747  unflipqueue->newindex((void **) &parybface);
27748  parybface->forg = ppt[0];
27749  parybface->fdest = ppt[1];
27750  parybface->fapex = ppt[2];
27751  parybface->foppo = ppt[3];
27752  parybface->tt.tet = parytet->tet;
27753  parybface->tt.ver = 11;
27754  parybface->key = maxcosd;
27755  for (i = 0; i < 6; i++) {
27756  parybface->cent[i] = cosdd[i];
27757  }
27758  }
27759  parytet = (triface *) badtetrahedrons->traverse();
27760  }
27761  badtetrahedrons->restart();
27762  } else {
27763  // Didn't split. Queue it again.
27764  unflipqueue->newindex((void **) &parybface);
27765  *parybface = *bface;
27766  } // if (j == 6)
27767  } // if (bface->key < cosslidihed)
27768  } // if (gettetrahedron(...))
27769  } // k
27770 
27771  flipqueue->restart();
27772 
27773  if (b->verbose > 1) {
27774  printf(" Split %ld tets.\n", sptcount);
27775  }
27776  totalsptcount += sptcount;
27777 
27778  if (sptcount == 0l) {
27779  // No point has been smoothed.
27780  break;
27781  } else {
27782  iter++;
27783  if (iter == 2) { //if (iter >= b->optpasses) {
27784  break;
27785  }
27786  }
27787 
27788  // Swap the two flip queues.
27789  swapqueue = flipqueue;
27790  flipqueue = unflipqueue;
27791  unflipqueue = swapqueue;
27792  } // while
27793 
27794  delete flipqueue;
27795 
27796  return totalsptcount;
27797 }
27798 
27800 // //
27801 // optimizemesh() Optimize mesh for specified objective functions. //
27802 // //
27804 
27805 void tetgenmesh::optimizemesh()
27806 {
27807  badface *parybface;
27808  triface checktet;
27809  point *ppt;
27810  int optpasses;
27811  optparameters opm;
27812  REAL ncosdd[6], maxdd;
27813  long totalremcount, remcount;
27814  long totalsmtcount, smtcount;
27815  long totalsptcount, sptcount;
27816  int chkencflag;
27817  int iter;
27818  int n;
27819 
27820  if (!b->quiet) {
27821  printf("Optimizing mesh...\n");
27822  }
27823 
27824  optpasses = ((1 << b->optlevel) - 1);
27825 
27826  if (b->verbose) {
27827  printf(" Optimization level = %d.\n", b->optlevel);
27828  printf(" Optimization scheme = %d.\n", b->optscheme);
27829  printf(" Number of iteration = %d.\n", optpasses);
27830  printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral);
27831  }
27832 
27833  totalsmtcount = totalsptcount = totalremcount = 0l;
27834 
27835  cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
27836  cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
27837  cosslidihed = cos(b->optminslidihed / 180.0 * PI);
27838 
27839  int attrnum = numelemattrib - 1;
27840 
27841  // Put all bad tetrahedra into array.
27842  tetrahedrons->traversalinit();
27843  checktet.tet = tetrahedrontraverse();
27844  while (checktet.tet != NULL) {
27845  if (b->convex) { // -c
27846  // Skip this tet if it lies in the exterior.
27847  if (elemattribute(checktet.tet, attrnum) == -1.0) {
27848  checktet.tet = tetrahedrontraverse();
27849  continue;
27850  }
27851  }
27852  ppt = (point *) & (checktet.tet[4]);
27853  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
27854  if (maxdd < cosmaxdihed) {
27855  // There are bad dihedral angles in this tet.
27856  unflipqueue->newindex((void **) &parybface);
27857  parybface->tt.tet = checktet.tet;
27858  parybface->tt.ver = 11;
27859  parybface->forg = ppt[0];
27860  parybface->fdest = ppt[1];
27861  parybface->fapex = ppt[2];
27862  parybface->foppo = ppt[3];
27863  parybface->key = maxdd;
27864  for (n = 0; n < 6; n++) {
27865  parybface->cent[n] = ncosdd[n];
27866  }
27867  }
27868  checktet.tet = tetrahedrontraverse();
27869  }
27870 
27871  totalremcount = improvequalitybyflips();
27872 
27873  if ((unflipqueue->objects > 0l) &&
27874  ((b->optscheme & 2) || (b->optscheme & 4))) {
27875  // The pool is only used by removeslivers().
27876  badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
27877  sizeof(void *), 0);
27878 
27879  // Smoothing options.
27880  opm.min_max_dihedangle = 1;
27881  opm.numofsearchdirs = 10;
27882  // opm.searchstep = 0.001;
27883  opm.maxiter = 30; // Limit the maximum iterations.
27884  //opm.checkencflag = 4; // Queue affected tets after smoothing.
27885  chkencflag = 4; // Queue affected tets after splitting a sliver.
27886  iter = 0;
27887 
27888  while (iter < optpasses) {
27889  smtcount = sptcount = remcount = 0l;
27890  if (b->optscheme & 2) {
27891  smtcount += improvequalitybysmoothing(&opm);
27892  totalsmtcount += smtcount;
27893  if (smtcount > 0l) {
27894  remcount = improvequalitybyflips();
27895  totalremcount += remcount;
27896  }
27897  }
27898  if (unflipqueue->objects > 0l) {
27899  if (b->optscheme & 4) {
27900  sptcount += removeslivers(chkencflag);
27901  totalsptcount += sptcount;
27902  if (sptcount > 0l) {
27903  remcount = improvequalitybyflips();
27904  totalremcount += remcount;
27905  }
27906  }
27907  }
27908  if (unflipqueue->objects > 0l) {
27909  if (remcount > 0l) {
27910  iter++;
27911  } else {
27912  break;
27913  }
27914  } else {
27915  break;
27916  }
27917  } // while (iter)
27918 
27919  delete badtetrahedrons;
27920  badtetrahedrons = NULL;
27921  }
27922 
27923  if (unflipqueue->objects > 0l) {
27924  if (b->verbose > 1) {
27925  printf(" %ld bad tets remained.\n", unflipqueue->objects);
27926  }
27927  unflipqueue->restart();
27928  }
27929 
27930  if (b->verbose) {
27931  if (totalremcount > 0l) {
27932  printf(" Removed %ld edges.\n", totalremcount);
27933  }
27934  if (totalsmtcount > 0l) {
27935  printf(" Smoothed %ld points.\n", totalsmtcount);
27936  }
27937  if (totalsptcount > 0l) {
27938  printf(" Split %ld slivers.\n", totalsptcount);
27939  }
27940  }
27941 }
27942 
27946 
27950 
27952 // //
27953 // printfcomma() Print a (large) number with the 'thousands separator'. //
27954 // //
27955 // The following code was simply copied from "stackoverflow". //
27956 // //
27958 
27959 void tetgenmesh::printfcomma(unsigned long n)
27960 {
27961  unsigned long n2 = 0;
27962  int scale = 1;
27963  while (n >= 1000) {
27964  n2 = n2 + scale * (n % 1000);
27965  n /= 1000;
27966  scale *= 1000;
27967  }
27968  printf ("%ld", n);
27969  while (scale != 1) {
27970  scale /= 1000;
27971  n = n2 / scale;
27972  n2 = n2 % scale;
27973  printf (",%03ld", n);
27974  }
27975 }
27976 
27978 // //
27979 // checkmesh() Test the mesh for topological consistency. //
27980 // //
27981 // If 'topoflag' is set, only check the topological connection of the mesh, //
27982 // i.e., do not report degenerated or inverted elements. //
27983 // //
27985 
27986 int tetgenmesh::checkmesh(int topoflag)
27987 {
27988  triface tetloop, neightet, symtet;
27989  point pa, pb, pc, pd;
27990  REAL ori;
27991  int horrors, i;
27992 
27993  if (!b->quiet) {
27994  printf(" Checking consistency of mesh...\n");
27995  }
27996 
27997  horrors = 0;
27998  tetloop.ver = 0;
27999  // Run through the list of tetrahedra, checking each one.
28000  tetrahedrons->traversalinit();
28001  tetloop.tet = alltetrahedrontraverse();
28002  while (tetloop.tet != (tetrahedron *) NULL) {
28003  // Check all four faces of the tetrahedron.
28004  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28005  pa = org(tetloop);
28006  pb = dest(tetloop);
28007  pc = apex(tetloop);
28008  pd = oppo(tetloop);
28009  if (tetloop.ver == 0) { // Only test for inversion once.
28010  if (!ishulltet(tetloop)) { // Only do test if it is not a hull tet.
28011  if (!topoflag) {
28012  ori = orient3d(pa, pb, pc, pd);
28013  if (ori >= 0.0) {
28014  printf(" !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
28015  printf(" (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
28016  pointmark(pb), pointmark(pc), pointmark(pd), ori);
28017  horrors++;
28018  }
28019  }
28020  }
28021  if (infected(tetloop)) {
28022  // This may be a bug. Report it.
28023  printf(" !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
28024  pointmark(pb), pointmark(pc), pointmark(pd));
28025  horrors++;
28026  }
28027  if (marktested(tetloop)) {
28028  // This may be a bug. Report it.
28029  printf(" !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
28030  pointmark(pb), pointmark(pc), pointmark(pd));
28031  horrors++;
28032  }
28033  }
28034  if (tetloop.tet[tetloop.ver] == NULL) {
28035  printf(" !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
28036  pointmark(pb), pointmark(pc));
28037  horrors++;
28038  } else {
28039  // Find the neighboring tetrahedron on this face.
28040  fsym(tetloop, neightet);
28041  if (neightet.tet != NULL) {
28042  // Check that the tetrahedron's neighbor knows it's a neighbor.
28043  fsym(neightet, symtet);
28044  if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
28045  printf(" !! !! Asymmetric tetra-tetra bond:\n");
28046  if (tetloop.tet == symtet.tet) {
28047  printf(" (Right tetrahedron, wrong orientation)\n");
28048  }
28049  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28050  pointmark(pb), pointmark(pc), pointmark(pd));
28051  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28052  pointmark(dest(neightet)), pointmark(apex(neightet)),
28053  pointmark(oppo(neightet)));
28054  horrors++;
28055  }
28056  // Check if they have the same edge (the bond() operation).
28057  if ((org(neightet) != pb) || (dest(neightet) != pa)) {
28058  printf(" !! !! Wrong edge-edge bond:\n");
28059  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28060  pointmark(pb), pointmark(pc), pointmark(pd));
28061  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28062  pointmark(dest(neightet)), pointmark(apex(neightet)),
28063  pointmark(oppo(neightet)));
28064  horrors++;
28065  }
28066  // Check if they have the same apex.
28067  if (apex(neightet) != pc) {
28068  printf(" !! !! Wrong face-face bond:\n");
28069  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28070  pointmark(pb), pointmark(pc), pointmark(pd));
28071  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28072  pointmark(dest(neightet)), pointmark(apex(neightet)),
28073  pointmark(oppo(neightet)));
28074  horrors++;
28075  }
28076  // Check if they have the same opposite.
28077  if (oppo(neightet) == pd) {
28078  printf(" !! !! Two identical tetra:\n");
28079  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28080  pointmark(pb), pointmark(pc), pointmark(pd));
28081  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28082  pointmark(dest(neightet)), pointmark(apex(neightet)),
28083  pointmark(oppo(neightet)));
28084  horrors++;
28085  }
28086  } else {
28087  printf(" !! !! Tet-face has no neighbor (%d, %d, %d) - %d:\n",
28088  pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd));
28089  horrors++;
28090  }
28091  }
28092  if (facemarked(tetloop)) {
28093  // This may be a bug. Report it.
28094  printf(" !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
28095  pointmark(pb), pointmark(pc), pointmark(pd));
28096  }
28097  }
28098  // Check the six edges of this tet.
28099  for (i = 0; i < 6; i++) {
28100  tetloop.ver = edge2ver[i];
28101  if (edgemarked(tetloop)) {
28102  // This may be a bug. Report it.
28103  printf(" !! tetedge (%d, %d) %d, %d is marked.\n",
28104  pointmark(org(tetloop)), pointmark(dest(tetloop)),
28105  pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
28106  }
28107  }
28108  tetloop.tet = alltetrahedrontraverse();
28109  }
28110  if (horrors == 0) {
28111  if (!b->quiet) {
28112  printf(" In my studied opinion, the mesh appears to be consistent.\n");
28113  }
28114  } else {
28115  printf(" !! !! !! !! %d %s witnessed.\n", horrors,
28116  horrors > 1 ? "abnormity" : "abnormities");
28117  }
28118 
28119  return horrors;
28120 }
28121 
28123 // //
28124 // checkshells() Test the boundary mesh for topological consistency. //
28125 // //
28127 
28128 int tetgenmesh::checkshells()
28129 {
28130  triface neightet, symtet;
28131  face shloop, spinsh, nextsh;
28132  face checkseg;
28133  point pa, pb;
28134  int bakcount;
28135  int horrors, i;
28136 
28137  if (!b->quiet) {
28138  printf(" Checking consistency of the mesh boundary...\n");
28139  }
28140  horrors = 0;
28141 
28142  void **bakpathblock = subfaces->pathblock;
28143  void *bakpathitem = subfaces->pathitem;
28144  int bakpathitemsleft = subfaces->pathitemsleft;
28145  int bakalignbytes = subfaces->alignbytes;
28146 
28147  subfaces->traversalinit();
28148  shloop.sh = shellfacetraverse(subfaces);
28149  while (shloop.sh != NULL) {
28150  shloop.shver = 0;
28151  for (i = 0; i < 3; i++) {
28152  // Check the face ring at this edge.
28153  pa = sorg(shloop);
28154  pb = sdest(shloop);
28155  spinsh = shloop;
28156  spivot(spinsh, nextsh);
28157  bakcount = horrors;
28158  while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
28159  if (nextsh.sh[3] == NULL) {
28160  printf(" !! !! Wrong subface-subface connection (Dead subface).\n");
28161  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28162  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28163  pointmark(sapex(spinsh)));
28164  printf(" Second: x%lx (DEAD)\n", (uintptr_t) nextsh.sh);
28165  horrors++;
28166  break;
28167  }
28168  // check if they have the same edge.
28169  if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) ||
28170  ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) {
28171  printf(" !! !! Wrong subface-subface connection.\n");
28172  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28173  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28174  pointmark(sapex(spinsh)));
28175  printf(" Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
28176  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
28177  pointmark(sapex(nextsh)));
28178  horrors++;
28179  break;
28180  }
28181  // Check they should not have the same apex.
28182  if (sapex(nextsh) == sapex(spinsh)) {
28183  printf(" !! !! Existing two duplicated subfaces.\n");
28184  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28185  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28186  pointmark(sapex(spinsh)));
28187  printf(" Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
28188  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
28189  pointmark(sapex(nextsh)));
28190  horrors++;
28191  break;
28192  }
28193  spinsh = nextsh;
28194  spivot(spinsh, nextsh);
28195  }
28196  // Check subface-subseg bond.
28197  sspivot(shloop, checkseg);
28198  if (checkseg.sh != NULL) {
28199  if (checkseg.sh[3] == NULL) {
28200  printf(" !! !! Wrong subface-subseg connection (Dead subseg).\n");
28201  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28202  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28203  pointmark(sapex(shloop)));
28204  printf(" Sub: x%lx (Dead)\n", (uintptr_t) checkseg.sh);
28205  horrors++;
28206  } else {
28207  if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) ||
28208  ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) {
28209  printf(" !! !! Wrong subface-subseg connection.\n");
28210  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28211  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28212  pointmark(sapex(shloop)));
28213  printf(" Seg: x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
28214  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
28215  horrors++;
28216  }
28217  }
28218  }
28219  if (horrors > bakcount) break; // An error detected.
28220  senextself(shloop);
28221  }
28222  // Check tet-subface connection.
28223  stpivot(shloop, neightet);
28224  if (neightet.tet != NULL) {
28225  if (neightet.tet[4] == NULL) {
28226  printf(" !! !! Wrong sub-to-tet connection (Dead tet)\n");
28227  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28228  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28229  pointmark(sapex(shloop)));
28230  printf(" Tet: x%lx (DEAD)\n", (uintptr_t) neightet.tet);
28231  horrors++;
28232  } else {
28233  if (!((sorg(shloop) == org(neightet)) &&
28234  (sdest(shloop) == dest(neightet)))) {
28235  printf(" !! !! Wrong sub-to-tet connection\n");
28236  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28237  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28238  pointmark(sapex(shloop)));
28239  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
28240  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28241  pointmark(dest(neightet)), pointmark(apex(neightet)),
28242  pointmark(oppo(neightet)));
28243  horrors++;
28244  }
28245  tspivot(neightet, spinsh);
28246  if (!((sorg(spinsh) == org(neightet)) &&
28247  (sdest(spinsh) == dest(neightet)))) {
28248  printf(" !! !! Wrong tet-sub connection.\n");
28249  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28250  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28251  pointmark(sapex(spinsh)));
28252  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
28253  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28254  pointmark(dest(neightet)), pointmark(apex(neightet)),
28255  pointmark(oppo(neightet)));
28256  horrors++;
28257  }
28258  fsym(neightet, symtet);
28259  tspivot(symtet, spinsh);
28260  if (spinsh.sh != NULL) {
28261  if (!((sorg(spinsh) == org(symtet)) &&
28262  (sdest(spinsh) == dest(symtet)))) {
28263  printf(" !! !! Wrong tet-sub connection.\n");
28264  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28265  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28266  pointmark(sapex(spinsh)));
28267  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
28268  (uintptr_t) symtet.tet, pointmark(org(symtet)),
28269  pointmark(dest(symtet)), pointmark(apex(symtet)),
28270  pointmark(oppo(symtet)));
28271  horrors++;
28272  }
28273  } else {
28274  printf(" Warning: Broken tet-sub-tet connection.\n");
28275  }
28276  }
28277  }
28278  if (sinfected(shloop)) {
28279  // This may be a bug. report it.
28280  printf(" !! A infected subface: (%d, %d, %d).\n",
28281  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28282  pointmark(sapex(shloop)));
28283  }
28284  if (smarktested(shloop)) {
28285  // This may be a bug. report it.
28286  printf(" !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)),
28287  pointmark(sdest(shloop)), pointmark(sapex(shloop)));
28288  }
28289  shloop.sh = shellfacetraverse(subfaces);
28290  }
28291 
28292  if (horrors == 0) {
28293  if (!b->quiet) {
28294  printf(" Mesh boundaries connected correctly.\n");
28295  }
28296  } else {
28297  printf(" !! !! !! !! %d boundary connection viewed with horror.\n",
28298  horrors);
28299  }
28300 
28301  subfaces->pathblock = bakpathblock;
28302  subfaces->pathitem = bakpathitem;
28303  subfaces->pathitemsleft = bakpathitemsleft;
28304  subfaces->alignbytes = bakalignbytes;
28305 
28306  return horrors;
28307 }
28308 
28310 // //
28311 // checksegments() Check the connections between tetrahedra and segments. //
28312 // //
28314 
28315 int tetgenmesh::checksegments()
28316 {
28317  triface tetloop, neightet, spintet;
28318  shellface *segs;
28319  face neighsh, spinsh, checksh;
28320  face sseg, checkseg;
28321  point pa, pb;
28322  int miscount;
28323  int t1ver;
28324  int horrors, i;
28325 
28326 
28327  if (!b->quiet) {
28328  printf(" Checking tet->seg connections...\n");
28329  }
28330 
28331  horrors = 0;
28332  tetrahedrons->traversalinit();
28333  tetloop.tet = tetrahedrontraverse();
28334  while (tetloop.tet != NULL) {
28335  // Loop the six edges of the tet.
28336  if (tetloop.tet[8] != NULL) {
28337  segs = (shellface *) tetloop.tet[8];
28338  for (i = 0; i < 6; i++) {
28339  sdecode(segs[i], sseg);
28340  if (sseg.sh != NULL) {
28341  // Get the edge of the tet.
28342  tetloop.ver = edge2ver[i];
28343  // Check if they are the same edge.
28344  pa = (point) sseg.sh[3];
28345  pb = (point) sseg.sh[4];
28346  if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
28347  ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
28348  printf(" !! Wrong tet-seg connection.\n");
28349  printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
28350  (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
28351  pointmark(dest(tetloop)), pointmark(apex(tetloop)),
28352  pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
28353  pointmark(pa), pointmark(pb));
28354  horrors++;
28355  } else {
28356  // Loop all tets sharing at this edge.
28357  neightet = tetloop;
28358  do {
28359  tsspivot1(neightet, checkseg);
28360  if (checkseg.sh != sseg.sh) {
28361  printf(" !! Wrong tet->seg connection.\n");
28362  printf(" Tet: x%lx (%d, %d, %d, %d) - ",
28363  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28364  pointmark(dest(neightet)), pointmark(apex(neightet)),
28365  pointmark(oppo(neightet)));
28366  if (checkseg.sh != NULL) {
28367  printf("Seg x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
28368  pointmark(sorg(checkseg)),pointmark(sdest(checkseg)));
28369  } else {
28370  printf("Seg: NULL.\n");
28371  }
28372  horrors++;
28373  }
28374  fnextself(neightet);
28375  } while (neightet.tet != tetloop.tet);
28376  }
28377  // Check the seg->tet pointer.
28378  sstpivot1(sseg, neightet);
28379  if (neightet.tet == NULL) {
28380  printf(" !! Wrong seg->tet connection (A NULL tet).\n");
28381  horrors++;
28382  } else {
28383  if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
28384  ((org(neightet) == pb) && (dest(neightet) == pa)))) {
28385  printf(" !! Wrong seg->tet connection (Wrong edge).\n");
28386  printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
28387  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28388  pointmark(dest(neightet)), pointmark(apex(neightet)),
28389  pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
28390  pointmark(pa), pointmark(pb));
28391  horrors++;
28392  }
28393  }
28394  }
28395  }
28396  }
28397  // Loop the six edge of this tet.
28398  neightet.tet = tetloop.tet;
28399  for (i = 0; i < 6; i++) {
28400  neightet.ver = edge2ver[i];
28401  if (edgemarked(neightet)) {
28402  // A possible bug. Report it.
28403  printf(" !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n",
28404  pointmark(org(neightet)), pointmark(dest(neightet)),
28405  pointmark(apex(neightet)), pointmark(oppo(neightet)),
28406  (uintptr_t) neightet.tet, neightet.ver);
28407  // Check if all tets at the edge are marked.
28408  spintet = neightet;
28409  while (1) {
28410  fnextself(spintet);
28411  if (!edgemarked(spintet)) {
28412  printf(" !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n",
28413  pointmark(org(spintet)), pointmark(dest(spintet)),
28414  pointmark(apex(spintet)), pointmark(oppo(spintet)),
28415  (uintptr_t) spintet.tet, spintet.ver);
28416  horrors++;
28417  }
28418  if (spintet.tet == neightet.tet) break;
28419  }
28420  }
28421  }
28422  tetloop.tet = tetrahedrontraverse();
28423  }
28424 
28425  if (!b->quiet) {
28426  printf(" Checking seg->tet connections...\n");
28427  }
28428 
28429  miscount = 0; // Count the number of unrecovered segments.
28430  subsegs->traversalinit();
28431  sseg.shver = 0;
28432  sseg.sh = shellfacetraverse(subsegs);
28433  while (sseg.sh != NULL) {
28434  pa = sorg(sseg);
28435  pb = sdest(sseg);
28436  spivot(sseg, neighsh);
28437  if (neighsh.sh != NULL) {
28438  spinsh = neighsh;
28439  while (1) {
28440  // Check seg-subface bond.
28441  if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
28442  ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
28443  // Keep the same rotate direction.
28444  //if (sorg(spinsh) != pa) {
28445  // sesymself(spinsh);
28446  // printf(" !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
28447  // pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28448  // pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
28449  // spinsh.shver);
28450  // horrors++;
28451  //}
28452  stpivot(spinsh, spintet);
28453  if (spintet.tet != NULL) {
28454  // Check if all tets at this segment.
28455  while (1) {
28456  tsspivot1(spintet, checkseg);
28457  if (checkseg.sh == NULL) {
28458  printf(" !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n",
28459  pointmark(org(spintet)), pointmark(dest(spintet)),
28460  pointmark(apex(spintet)), pointmark(oppo(spintet)),
28461  (uintptr_t) spintet.tet, spintet.ver);
28462  horrors++;
28463  }
28464  if (checkseg.sh != sseg.sh) {
28465  printf(" !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
28466  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
28467  pointmark(org(spintet)), pointmark(dest(spintet)),
28468  pointmark(apex(spintet)), pointmark(oppo(spintet)));
28469  horrors++;
28470  }
28471  fnextself(spintet);
28472  // Stop at the next subface.
28473  tspivot(spintet, checksh);
28474  if (checksh.sh != NULL) break;
28475  } // while (1)
28476  }
28477  } else {
28478  printf(" !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
28479  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28480  pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
28481  spinsh.shver);
28482  horrors++;
28483  break;
28484  } // if pa, pb
28485  spivotself(spinsh);
28486  if (spinsh.sh == NULL) break; // A dangling segment.
28487  if (spinsh.sh == neighsh.sh) break;
28488  } // while (1)
28489  } // if (neighsh.sh != NULL)
28490  // Count the number of "un-recovered" segments.
28491  sstpivot1(sseg, neightet);
28492  if (neightet.tet == NULL) {
28493  miscount++;
28494  }
28495  sseg.sh = shellfacetraverse(subsegs);
28496  }
28497 
28498  if (!b->quiet) {
28499  printf(" Checking seg->seg connections...\n");
28500  }
28501 
28502  points->traversalinit();
28503  pa = pointtraverse();
28504  while (pa != NULL) {
28505  if (pointtype(pa) == FREESEGVERTEX) {
28506  // There should be two subsegments connected at 'pa'.
28507  // Get a subsegment containing 'pa'.
28508  sdecode(point2sh(pa), sseg);
28509  if ((sseg.sh == NULL) || sseg.sh[3] == NULL) {
28510  printf(" !! Dead point-to-seg pointer at point %d.\n",
28511  pointmark(pa));
28512  horrors++;
28513  } else {
28514  sseg.shver = 0;
28515  if (sorg(sseg) != pa) {
28516  if (sdest(sseg) != pa) {
28517  printf(" !! Wrong point-to-seg pointer at point %d.\n",
28518  pointmark(pa));
28519  horrors++;
28520  } else {
28521  // Find the next subsegment at 'pa'.
28522  senext(sseg, checkseg);
28523  if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
28524  printf(" !! Dead seg-seg connection at point %d.\n",
28525  pointmark(pa));
28526  horrors++;
28527  } else {
28528  spivotself(checkseg);
28529  checkseg.shver = 0;
28530  if ((sorg(checkseg) != pa) && (sdest(checkseg) != pa)) {
28531  printf(" !! Wrong seg-seg connection at point %d.\n",
28532  pointmark(pa));
28533  horrors++;
28534  }
28535  }
28536  }
28537  } else {
28538  // Find the previous subsegment at 'pa'.
28539  senext2(sseg, checkseg);
28540  if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
28541  printf(" !! Dead seg-seg connection at point %d.\n",
28542  pointmark(pa));
28543  horrors++;
28544  } else {
28545  spivotself(checkseg);
28546  checkseg.shver = 0;
28547  if ((sorg(checkseg) != pa) && (sdest(checkseg) != pa)) {
28548  printf(" !! Wrong seg-seg connection at point %d.\n",
28549  pointmark(pa));
28550  horrors++;
28551  }
28552  }
28553  }
28554  }
28555  }
28556  pa = pointtraverse();
28557  }
28558 
28559  if (horrors == 0) {
28560  printf(" Segments are connected properly.\n");
28561  } else {
28562  printf(" !! !! !! !! Found %d missing connections.\n", horrors);
28563  }
28564  if (miscount > 0) {
28565  printf(" !! !! Found %d missing segments.\n", miscount);
28566  }
28567 
28568  return horrors;
28569 }
28570 
28572 // //
28573 // checkdelaunay() Ensure that the mesh is (constrained) Delaunay. //
28574 // //
28576 
28577 int tetgenmesh::checkdelaunay(int perturb)
28578 {
28579  triface tetloop;
28580  triface symtet;
28581  face checksh;
28582  point pa, pb, pc, pd, pe;
28583  REAL sign;
28584  int ndcount; // Count the non-locally Delaunay faces.
28585  int horrors;
28586 
28587  if (!b->quiet) {
28588  printf(" Checking Delaunay property of the mesh...\n");
28589  }
28590 
28591  ndcount = 0;
28592  horrors = 0;
28593  tetloop.ver = 0;
28594  // Run through the list of triangles, checking each one.
28595  tetrahedrons->traversalinit();
28596  tetloop.tet = tetrahedrontraverse();
28597  while (tetloop.tet != (tetrahedron *) NULL) {
28598  // Check all four faces of the tetrahedron.
28599  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28600  fsym(tetloop, symtet);
28601  // Only do test if its adjoining tet is not a hull tet or its pointer
28602  // is larger (to ensure that each pair isn't tested twice).
28603  if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
28604  pa = org(tetloop);
28605  pb = dest(tetloop);
28606  pc = apex(tetloop);
28607  pd = oppo(tetloop);
28608  pe = oppo(symtet);
28609  if (perturb) {
28610  sign = insphere_s(pa, pb, pc, pd, pe);
28611  } else {
28612  sign = insphere(pa, pb, pc, pd, pe);
28613  }
28614  if (sign < 0.0) {
28615  ndcount++;
28616  if (checksubfaceflag) {
28617  tspivot(tetloop, checksh);
28618  }
28619  if (checksh.sh == NULL) {
28620  printf(" !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
28621  pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
28622  pointmark(pe));
28623  horrors++;
28624  }
28625  }
28626  }
28627  }
28628  tetloop.tet = tetrahedrontraverse();
28629  }
28630 
28631  if (horrors == 0) {
28632  if (!b->quiet) {
28633  if (ndcount > 0) {
28634  printf(" The mesh is constrained Delaunay.\n");
28635  } else {
28636  printf(" The mesh is Delaunay.\n");
28637  }
28638  }
28639  } else {
28640  printf(" !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
28641  }
28642 
28643  return horrors;
28644 }
28645 
28647 // //
28648 // Check if the current tetrahedralization is (constrained) regular. //
28649 // //
28650 // The parameter 'type' determines which regularity should be checked: //
28651 // - 0: check the Delaunay property. //
28652 // - 1: check the Delaunay property with symbolic perturbation. //
28653 // - 2: check the regular property, the weights are stored in p[3]. //
28654 // - 3: check the regular property with symbolic perturbation. //
28655 // //
28657 
28658 int tetgenmesh::checkregular(int type)
28659 {
28660  triface tetloop;
28661  triface symtet;
28662  face checksh;
28663  point p[5];
28664  REAL sign;
28665  int ndcount; // Count the non-locally Delaunay faces.
28666  int horrors;
28667 
28668  if (!b->quiet) {
28669  printf(" Checking %s %s property of the mesh...\n",
28670  (type & 2) == 0 ? "Delaunay" : "regular",
28671  (type & 1) == 0 ? " " : "(s)");
28672  }
28673 
28674  // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
28675  // Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
28676  // p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
28677  // The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
28678  // p[4] lies below the oriented hyperplane passing through
28679  // p[1], p[0], p[2], p[3].
28680 
28681  ndcount = 0;
28682  horrors = 0;
28683  tetloop.ver = 0;
28684  // Run through the list of triangles, checking each one.
28685  tetrahedrons->traversalinit();
28686  tetloop.tet = tetrahedrontraverse();
28687  while (tetloop.tet != (tetrahedron *) NULL) {
28688  // Check all four faces of the tetrahedron.
28689  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28690  fsym(tetloop, symtet);
28691  // Only do test if its adjoining tet is not a hull tet or its pointer
28692  // is larger (to ensure that each pair isn't tested twice).
28693  if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
28694  p[0] = org(tetloop); // pa
28695  p[1] = dest(tetloop); // pb
28696  p[2] = apex(tetloop); // pc
28697  p[3] = oppo(tetloop); // pd
28698  p[4] = oppo(symtet); // pe
28699 
28700  if (type == 0) {
28701  sign = insphere(p[1], p[0], p[2], p[3], p[4]);
28702  } else if (type == 1) {
28703  sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
28704  } else if (type == 2) {
28705  sign = orient4d(p[1], p[0], p[2], p[3], p[4],
28706  p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
28707  } else { // type == 3
28708  sign = orient4d_s(p[1], p[0], p[2], p[3], p[4],
28709  p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
28710  }
28711 
28712  if (sign > 0.0) {
28713  ndcount++;
28714  if (checksubfaceflag) {
28715  tspivot(tetloop, checksh);
28716  }
28717  if (checksh.sh == NULL) {
28718  printf(" !! Non-locally %s (%d, %d, %d) - %d, %d\n",
28719  (type & 2) == 0 ? "Delaunay" : "regular",
28720  pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
28721  pointmark(p[3]), pointmark(p[4]));
28722  horrors++;
28723  }
28724  }
28725  }
28726  }
28727  tetloop.tet = tetrahedrontraverse();
28728  }
28729 
28730  if (horrors == 0) {
28731  if (!b->quiet) {
28732  if (ndcount > 0) {
28733  printf(" The mesh is constrained %s.\n",
28734  (type & 2) == 0 ? "Delaunay" : "regular");
28735  } else {
28736  printf(" The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
28737  }
28738  }
28739  } else {
28740  printf(" !! !! !! !! Found %d non-%s faces.\n", horrors,
28741  (type & 2) == 0 ? "Delaunay" : "regular");
28742  }
28743 
28744  return horrors;
28745 }
28746 
28748 // //
28749 // checkconforming() Ensure that the mesh is conforming Delaunay. //
28750 // //
28751 // If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces. //
28752 // If 'flag' is 3, check both subsegments and subfaces. //
28753 // //
28755 
28756 int tetgenmesh::checkconforming(int flag)
28757 {
28758  triface searchtet, neightet, spintet;
28759  face shloop;
28760  face segloop;
28761  point eorg, edest, eapex, pa, pb, pc;
28762  REAL cent[3], radius, dist, diff, rd, len;
28763  bool enq;
28764  int encsubsegs, encsubfaces;
28765  int t1ver;
28766  int i;
28767 
28768  REAL A[4][4], rhs[4], D;
28769  int indx[4];
28770  REAL elen[3];
28771 
28772  encsubsegs = 0;
28773 
28774  if (flag & 1) {
28775  if (!b->quiet) {
28776  printf(" Checking conforming property of segments...\n");
28777  }
28778  encsubsegs = 0;
28779 
28780  // Run through the list of subsegments, check each one.
28781  subsegs->traversalinit();
28782  segloop.sh = shellfacetraverse(subsegs);
28783  while (segloop.sh != (shellface *) NULL) {
28784  eorg = (point) segloop.sh[3];
28785  edest = (point) segloop.sh[4];
28786  radius = 0.5 * distance(eorg, edest);
28787  for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
28788 
28789  enq = false;
28790  sstpivot1(segloop, neightet);
28791  if (neightet.tet != NULL) {
28792  spintet = neightet;
28793  while (1) {
28794  eapex= apex(spintet);
28795  if (eapex != dummypoint) {
28796  dist = distance(eapex, cent);
28797  diff = dist - radius;
28798  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28799  if (diff < 0) {
28800  enq = true; break;
28801  }
28802  }
28803  fnextself(spintet);
28804  if (spintet.tet == neightet.tet) break;
28805  }
28806  }
28807  if (enq) {
28808  printf(" !! !! Non-conforming segment: (%d, %d)\n",
28809  pointmark(eorg), pointmark(edest));
28810  encsubsegs++;
28811  }
28812  segloop.sh = shellfacetraverse(subsegs);
28813  }
28814 
28815  if (encsubsegs == 0) {
28816  if (!b->quiet) {
28817  printf(" The segments are conforming Delaunay.\n");
28818  }
28819  } else {
28820  printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs);
28821  }
28822  } // if (flag & 1)
28823 
28824  encsubfaces = 0;
28825 
28826  if (flag & 2) {
28827  if (!b->quiet) {
28828  printf(" Checking conforming property of subfaces...\n");
28829  }
28830 
28831  // Run through the list of subfaces, check each one.
28832  subfaces->traversalinit();
28833  shloop.sh = shellfacetraverse(subfaces);
28834  while (shloop.sh != (shellface *) NULL) {
28835  pa = (point) shloop.sh[3];
28836  pb = (point) shloop.sh[4];
28837  pc = (point) shloop.sh[5];
28838 
28839  // Compute the coefficient matrix A (3x3).
28840  A[0][0] = pb[0] - pa[0];
28841  A[0][1] = pb[1] - pa[1];
28842  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
28843  A[1][0] = pc[0] - pa[0];
28844  A[1][1] = pc[1] - pa[1];
28845  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
28846  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
28847 
28848  // Compute the right hand side vector b (3x1).
28849  elen[0] = dot(A[0], A[0]);
28850  elen[1] = dot(A[1], A[1]);
28851  rhs[0] = 0.5 * elen[0];
28852  rhs[1] = 0.5 * elen[1];
28853  rhs[2] = 0.0;
28854 
28855  if (lu_decmp(A, 3, indx, &D, 0)) {
28856  lu_solve(A, 3, indx, rhs, 0);
28857  cent[0] = pa[0] + rhs[0];
28858  cent[1] = pa[1] + rhs[1];
28859  cent[2] = pa[2] + rhs[2];
28860  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
28861 
28862  // Check if this subface is encroached.
28863  for (i = 0; i < 2; i++) {
28864  stpivot(shloop, searchtet);
28865  if (!ishulltet(searchtet)) {
28866  len = distance(oppo(searchtet), cent);
28867  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
28868  if (len < rd) {
28869  printf(" !! !! Non-conforming subface: (%d, %d, %d)\n",
28870  pointmark(pa), pointmark(pb), pointmark(pc));
28871  encsubfaces++;
28872  enq = true; break;
28873  }
28874  }
28875  sesymself(shloop);
28876  }
28877  }
28878  shloop.sh = shellfacetraverse(subfaces);
28879  }
28880 
28881  if (encsubfaces == 0) {
28882  if (!b->quiet) {
28883  printf(" The subfaces are conforming Delaunay.\n");
28884  }
28885  } else {
28886  printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces);
28887  }
28888  } // if (flag & 2)
28889 
28890  return encsubsegs + encsubfaces;
28891 }
28892 
28894 // //
28895 // qualitystatistics() Print statistics about the quality of the mesh. //
28896 // //
28898 
28899 void tetgenmesh::qualitystatistics()
28900 {
28901  triface tetloop, neightet;
28902  point p[4];
28903  char sbuf[128];
28904  REAL radiusratiotable[12];
28905  REAL aspectratiotable[12];
28906  REAL A[4][4], rhs[4], D;
28907  REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
28908  REAL edgelength[6], alldihed[6], faceangle[3];
28909  REAL shortest, longest;
28910  REAL smallestvolume, biggestvolume;
28911  REAL smallestratio, biggestratio;
28912  REAL smallestradiusratio, biggestradiusratio; // radius-edge ratio.
28913  REAL smallestdiangle, biggestdiangle;
28914  REAL smallestfaangle, biggestfaangle;
28915  REAL total_tet_vol, total_tetprism_vol;
28916  REAL tetvol, minaltitude;
28917  REAL cirradius, minheightinv; // insradius;
28918  REAL shortlen, longlen;
28919  REAL tetaspect, tetradius;
28920  REAL smalldiangle, bigdiangle;
28921  REAL smallfaangle, bigfaangle;
28922  unsigned long radiustable[12];
28923  unsigned long aspecttable[16];
28924  unsigned long dihedangletable[18];
28925  unsigned long faceangletable[18];
28926  int indx[4];
28927  int radiusindex;
28928  int aspectindex;
28929  int tendegree;
28930  int i, j;
28931  // Report the tet which has the biggest radius-edge ratio.
28932  triface biggestradiusratiotet;
28933 
28934  printf("Mesh quality statistics:\n\n");
28935 
28936  shortlen = longlen = 0.0;
28937  smalldiangle = bigdiangle = 0.0;
28938  total_tet_vol = 0.0;
28939  total_tetprism_vol = 0.0;
28940 
28941  radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0;
28942  radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2;
28943  radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6;
28944  radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0;
28945  radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0;
28946  radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0;
28947 
28948  aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0;
28949  aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0;
28950  aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0;
28951  aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0;
28952  aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0;
28953  aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0;
28954 
28955  for (i = 0; i < 12; i++) radiustable[i] = 0l;
28956  for (i = 0; i < 12; i++) aspecttable[i] = 0l;
28957  for (i = 0; i < 18; i++) dihedangletable[i] = 0l;
28958  for (i = 0; i < 18; i++) faceangletable[i] = 0l;
28959 
28960  minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
28961  minaltitude = minaltitude * minaltitude;
28962  shortest = minaltitude;
28963  longest = 0.0;
28964  smallestvolume = minaltitude;
28965  biggestvolume = 0.0;
28966  smallestratio = smallestradiusratio = 1e+16; // minaltitude;
28967  biggestratio = biggestradiusratio = 0.0;
28968  smallestdiangle = smallestfaangle = 180.0;
28969  biggestdiangle = biggestfaangle = 0.0;
28970 
28971 
28972  int attrnum = numelemattrib - 1;
28973 
28974  // Loop all elements, calculate quality parameters for each element.
28975  tetrahedrons->traversalinit();
28976  tetloop.tet = tetrahedrontraverse();
28977  while (tetloop.tet != (tetrahedron *) NULL) {
28978 
28979  if (b->convex) {
28980  // Skip tets in the exterior.
28981  if (elemattribute(tetloop.tet, attrnum) == -1.0) {
28982  tetloop.tet = tetrahedrontraverse();
28983  continue;
28984  }
28985  }
28986 
28987  // Get four vertices: p0, p1, p2, p3.
28988  for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
28989 
28990  // Get the tet volume.
28991  tetvol = orient3dfast(p[1], p[0], p[2], p[3]) / 6.0;
28992  total_tet_vol += tetvol;
28993  total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
28994 
28995  // Calculate the largest and smallest volume.
28996  if (tetvol < smallestvolume) {
28997  smallestvolume = tetvol;
28998  }
28999  if (tetvol > biggestvolume) {
29000  biggestvolume = tetvol;
29001  }
29002 
29003  // Set the edge vectors: V[0], ..., V[5]
29004  for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
29005  for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
29006  for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
29007  for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
29008  for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
29009  for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
29010 
29011  // Get the squares of the edge lengths.
29012  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
29013 
29014  // Calculate the longest and shortest edge length.
29015  for (i = 0; i < 6; i++) {
29016  if (i == 0) {
29017  shortlen = longlen = edgelength[i];
29018  } else {
29019  shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
29020  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
29021  }
29022  if (edgelength[i] > longest) {
29023  longest = edgelength[i];
29024  }
29025  if (edgelength[i] < shortest) {
29026  shortest = edgelength[i];
29027  }
29028  }
29029 
29030  // Set the matrix A = [V[0], V[1], V[2]]^T.
29031  for (j = 0; j < 3; j++) {
29032  for (i = 0; i < 3; i++) A[j][i] = V[j][i];
29033  }
29034 
29035  // Decompose A just once.
29036  if (lu_decmp(A, 3, indx, &D, 0)) {
29037  // Get the three faces normals.
29038  for (j = 0; j < 3; j++) {
29039  for (i = 0; i < 3; i++) rhs[i] = 0.0;
29040  rhs[j] = 1.0; // Positive means the inside direction
29041  lu_solve(A, 3, indx, rhs, 0);
29042  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
29043  }
29044  // Get the fourth face normal by summing up the first three.
29045  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
29046  // Get the radius of the circumsphere.
29047  for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
29048  lu_solve(A, 3, indx, rhs, 0);
29049  cirradius = sqrt(dot(rhs, rhs));
29050  // Normalize the face normals.
29051  for (i = 0; i < 4; i++) {
29052  // H[i] is the inverse of height of its corresponding face.
29053  H[i] = sqrt(dot(N[i], N[i]));
29054  for (j = 0; j < 3; j++) N[i][j] /= H[i];
29055  }
29056  // Get the radius of the inscribed sphere.
29057  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
29058  // Get the biggest H[i] (corresponding to the smallest height).
29059  minheightinv = H[0];
29060  for (i = 1; i < 4; i++) {
29061  if (H[i] > minheightinv) minheightinv = H[i];
29062  }
29063  } else {
29064  // A nearly degenerated tet.
29065  if (tetvol <= 0.0) {
29066  printf(" !! Warning: A %s tet (%d,%d,%d,%d).\n",
29067  tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
29068  pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
29069  // Skip it.
29070  tetloop.tet = tetrahedrontraverse();
29071  continue;
29072  }
29073  // Calculate the four face normals.
29074  facenormal(p[2], p[1], p[3], N[0], 1, NULL);
29075  facenormal(p[0], p[2], p[3], N[1], 1, NULL);
29076  facenormal(p[1], p[0], p[3], N[2], 1, NULL);
29077  facenormal(p[0], p[1], p[2], N[3], 1, NULL);
29078  // Normalize the face normals.
29079  for (i = 0; i < 4; i++) {
29080  // H[i] is the twice of the area of the face.
29081  H[i] = sqrt(dot(N[i], N[i]));
29082  for (j = 0; j < 3; j++) N[i][j] /= H[i];
29083  }
29084  // Get the biggest H[i] / tetvol (corresponding to the smallest height).
29085  minheightinv = (H[0] / tetvol);
29086  for (i = 1; i < 4; i++) {
29087  if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
29088  }
29089  // Let the circumradius to be the half of its longest edge length.
29090  cirradius = 0.5 * sqrt(longlen);
29091  }
29092 
29093  // Get the dihedrals (in degree) at each edges.
29094  j = 0;
29095  for (i = 1; i < 4; i++) {
29096  alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
29097  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
29098  else if (alldihed[j] > 1.0) alldihed[j] = 1;
29099  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
29100  j++;
29101  }
29102  for (i = 2; i < 4; i++) {
29103  alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
29104  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
29105  else if (alldihed[j] > 1.0) alldihed[j] = 1;
29106  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
29107  j++;
29108  }
29109  alldihed[j] = -dot(N[2], N[3]); // Edge ab.
29110  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
29111  else if (alldihed[j] > 1.0) alldihed[j] = 1;
29112  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
29113 
29114  // Calculate the largest and smallest dihedral angles.
29115  for (i = 0; i < 6; i++) {
29116  if (i == 0) {
29117  smalldiangle = bigdiangle = alldihed[i];
29118  } else {
29119  smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
29120  bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
29121  }
29122  if (alldihed[i] < smallestdiangle) {
29123  smallestdiangle = alldihed[i];
29124  }
29125  if (alldihed[i] > biggestdiangle) {
29126  biggestdiangle = alldihed[i];
29127  }
29128  // Accumulate the corresponding number in the dihedral angle histogram.
29129  if (alldihed[i] < 5.0) {
29130  tendegree = 0;
29131  } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
29132  tendegree = 1;
29133  } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
29134  tendegree = 9; // Angles between 80 to 110 degree are in one entry.
29135  } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
29136  tendegree = 16;
29137  } else if (alldihed[i] >= 175.0) {
29138  tendegree = 17;
29139  } else {
29140  tendegree = (int) (alldihed[i] / 10.);
29141  if (alldihed[i] < 80.0) {
29142  tendegree++; // In the left column.
29143  } else {
29144  tendegree--; // In the right column.
29145  }
29146  }
29147  dihedangletable[tendegree]++;
29148  }
29149 
29150 
29151 
29152  // Calculate the largest and smallest face angles.
29153  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
29154  fsym(tetloop, neightet);
29155  // Only do the calulation once for a face.
29156  if (((point) neightet.tet[7] == dummypoint) ||
29157  (tetloop.tet < neightet.tet)) {
29158  p[0] = org(tetloop);
29159  p[1] = dest(tetloop);
29160  p[2] = apex(tetloop);
29161  faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
29162  faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
29163  faceangle[2] = PI - (faceangle[0] + faceangle[1]);
29164  // Translate angles into degrees.
29165  for (i = 0; i < 3; i++) {
29166  faceangle[i] = (faceangle[i] * 180.0) / PI;
29167  }
29168  // Calculate the largest and smallest face angles.
29169  for (i = 0; i < 3; i++) {
29170  if (i == 0) {
29171  smallfaangle = bigfaangle = faceangle[i];
29172  } else {
29173  smallfaangle = faceangle[i] < smallfaangle ?
29174  faceangle[i] : smallfaangle;
29175  bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
29176  }
29177  if (faceangle[i] < smallestfaangle) {
29178  smallestfaangle = faceangle[i];
29179  }
29180  if (faceangle[i] > biggestfaangle) {
29181  biggestfaangle = faceangle[i];
29182  }
29183  tendegree = (int) (faceangle[i] / 10.);
29184  faceangletable[tendegree]++;
29185  }
29186  }
29187  }
29188 
29189  // Calculate aspect ratio and radius-edge ratio for this element.
29190  tetradius = cirradius / sqrt(shortlen);
29191  if (tetradius < smallestradiusratio) {
29192  smallestradiusratio = tetradius;
29193  }
29194  if (tetradius > biggestradiusratio) {
29195  biggestradiusratio = tetradius;
29196  biggestradiusratiotet.tet = tetloop.tet;
29197  }
29198  // tetaspect = sqrt(longlen) / (2.0 * insradius);
29199  tetaspect = sqrt(longlen) * minheightinv;
29200  // Remember the largest and smallest aspect ratio.
29201  if (tetaspect < smallestratio) {
29202  smallestratio = tetaspect;
29203  }
29204  if (tetaspect > biggestratio) {
29205  biggestratio = tetaspect;
29206  }
29207  // Accumulate the corresponding number in the aspect ratio histogram.
29208  aspectindex = 0;
29209  while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
29210  aspectindex++;
29211  }
29212  aspecttable[aspectindex]++;
29213  radiusindex = 0;
29214  while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
29215  radiusindex++;
29216  }
29217  radiustable[radiusindex]++;
29218 
29219  tetloop.tet = tetrahedrontraverse();
29220  }
29221 
29222  shortest = sqrt(shortest);
29223  longest = sqrt(longest);
29224  minaltitude = sqrt(minaltitude);
29225 
29226  printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n",
29227  smallestvolume, biggestvolume);
29228  printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
29229  shortest, longest);
29230  printf(" Smallest asp.ratio: %13.5g | Largest asp.ratio: %13.5g\n",
29231  smallestratio, biggestratio);
29232  sprintf(sbuf, "%.17g", biggestfaangle);
29233  if (strlen(sbuf) > 8) {
29234  sbuf[8] = '\0';
29235  }
29236  printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
29237  smallestfaangle, sbuf);
29238  sprintf(sbuf, "%.17g", biggestdiangle);
29239  if (strlen(sbuf) > 8) {
29240  sbuf[8] = '\0';
29241  }
29242  printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
29243  smallestdiangle, sbuf);
29244 
29245  printf(" Aspect ratio histogram:\n");
29246  printf(" < %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
29247  aspectratiotable[0], aspecttable[0], aspectratiotable[5],
29248  aspectratiotable[6], aspecttable[6]);
29249  for (i = 1; i < 5; i++) {
29250  printf(" %6.6g - %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
29251  aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
29252  aspectratiotable[i + 5], aspectratiotable[i + 6],
29253  aspecttable[i + 6]);
29254  }
29255  printf(" %6.6g - %-6.6g : %8ld | %6.6g - : %8ld\n",
29256  aspectratiotable[4], aspectratiotable[5], aspecttable[5],
29257  aspectratiotable[10], aspecttable[11]);
29258  printf(" (A tetrahedron's aspect ratio is its longest edge length");
29259  printf(" divided by its\n");
29260  printf(" smallest side height)\n\n");
29261 
29262  printf(" Face angle histogram:\n");
29263  for (i = 0; i < 9; i++) {
29264  printf(" %3d - %3d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29265  i * 10, i * 10 + 10, faceangletable[i],
29266  i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
29267  }
29268  if (minfaceang != PI) {
29269  printf(" Minimum input face angle is %g (degree).\n",
29270  minfaceang / PI * 180.0);
29271  }
29272  printf("\n");
29273 
29274  printf(" Dihedral angle histogram:\n");
29275  // Print the three two rows:
29276  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29277  0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
29278  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29279  5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
29280  // Print the third to seventh rows.
29281  for (i = 2; i < 7; i++) {
29282  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29283  (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
29284  (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
29285  }
29286  // Print the last two rows.
29287  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29288  60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
29289  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29290  70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
29291  if (minfacetdihed != PI) {
29292  printf(" Minimum input dihedral angle is %g (degree).\n",
29293  minfacetdihed / PI * 180.0);
29294  }
29295  printf("\n");
29296 
29297  printf("\n");
29298 }
29299 
29300 
29302 // //
29303 // memorystatistics() Report the memory usage. //
29304 // //
29306 
29307 void tetgenmesh::memorystatistics()
29308 {
29309  printf("Memory usage statistics:\n\n");
29310 
29311  // Count the number of blocks of tetrahedra.
29312  int tetblocks = 0;
29313  tetrahedrons->pathblock = tetrahedrons->firstblock;
29314  while (tetrahedrons->pathblock != NULL) {
29315  tetblocks++;
29316  tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);
29317  }
29318 
29319  // Calculate the total memory (in bytes) used by storing meshes.
29320  unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
29321  totalmeshmemory = points->maxitems * points->itembytes +
29322  tetrahedrons->maxitems * tetrahedrons->itembytes;
29323  if (b->plc || b->refine) {
29324  totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
29325  subsegs->maxitems * subsegs->itembytes);
29326  totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
29327  tet2segpool->maxitems * tet2segpool->itembytes);
29328  }
29329 
29330  unsigned long totalalgomemory = 0l;
29331  totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
29332  caveoldtetlist->totalmemory +
29333  flippool->maxitems * flippool->itembytes;
29334  if (b->plc || b->refine) {
29335  totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
29336  subvertstack->totalmemory +
29337  caveshlist->totalmemory + caveshbdlist->totalmemory +
29338  cavesegshlist->totalmemory +
29339  cavetetshlist->totalmemory +
29340  cavetetseglist->totalmemory +
29341  caveencshlist->totalmemory +
29342  caveencseglist->totalmemory +
29343  cavetetvertlist->totalmemory +
29344  unflipqueue->totalmemory);
29345  }
29346 
29347  printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
29348  printf(" Maximum number of tet blocks (blocksize = %d): %d\n",
29349  b->tetrahedraperblock, tetblocks);
29350  /*
29351  if (b->plc || b->refine) {
29352  printf(" Approximate memory for tetrahedral mesh (bytes): %ld\n",
29353  totalmeshmemory);
29354 
29355  printf(" Approximate memory for extra pointers (bytes): %ld\n",
29356  totalt2shmemory);
29357  } else {
29358  printf(" Approximate memory for tetrahedralization (bytes): %ld\n",
29359  totalmeshmemory);
29360  }
29361  printf(" Approximate memory for algorithms (bytes): %ld\n",
29362  totalalgomemory);
29363  printf(" Approximate memory for working arrays (bytes): %ld\n",
29364  totalworkmemory);
29365  printf(" Approximate total used memory (bytes): %ld\n",
29366  totalmeshmemory + totalt2shmemory + totalalgomemory +
29367  totalworkmemory);
29368  */
29369  if (b->plc || b->refine) {
29370  printf(" Approximate memory for tetrahedral mesh (bytes): ");
29371  printfcomma(totalmeshmemory); printf("\n");
29372 
29373  printf(" Approximate memory for extra pointers (bytes): ");
29374  printfcomma(totalt2shmemory); printf("\n");
29375  } else {
29376  printf(" Approximate memory for tetrahedralization (bytes): ");
29377  printfcomma(totalmeshmemory); printf("\n");
29378  }
29379  printf(" Approximate memory for algorithms (bytes): ");
29380  printfcomma(totalalgomemory); printf("\n");
29381  printf(" Approximate memory for working arrays (bytes): ");
29382  printfcomma(totalworkmemory); printf("\n");
29383  printf(" Approximate total used memory (bytes): ");
29384  printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory +
29385  totalworkmemory);
29386  printf("\n");
29387 
29388  printf("\n");
29389 }
29390 
29392 // //
29393 // statistics() Print all sorts of cool facts. //
29394 // //
29396 
29397 void tetgenmesh::statistics()
29398 {
29399  long tetnumber, facenumber;
29400 
29401  printf("\nStatistics:\n\n");
29402  printf(" Input points: %d\n", in->numberofpoints);
29403  if (b->refine) {
29404  printf(" Input tetrahedra: %d\n", in->numberoftetrahedra);
29405  if (in->numberoftrifaces > 0) {
29406  printf(" Input triangles: %d\n", in->numberoftrifaces);
29407  }
29408  if (in->numberofedges > 0) {
29409  printf(" Input edges: %d\n", in->numberofedges);
29410  }
29411  } else if (b->plc) {
29412  printf(" Input facets: %d\n", in->numberoffacets);
29413  printf(" Input segments: %ld\n", insegments);
29414  if (in->numberofedges > 0) {
29415  printf(" Input edges: %d\n", in->numberofedges);
29416  }
29417  printf(" Input holes: %d\n", in->numberofholes);
29418  printf(" Input regions: %d\n", in->numberofregions);
29419  }
29420 
29421  tetnumber = tetrahedrons->items - hullsize;
29422  facenumber = (tetnumber * 4l + hullsize) / 2l;
29423 
29424  if (b->weighted) { // -w option
29425  printf("\n Mesh points: %ld\n", points->items - nonregularcount);
29426  } else {
29427  printf("\n Mesh points: %ld\n", points->items);
29428  }
29429  printf(" Mesh tetrahedra: %ld\n", tetnumber);
29430  printf(" Mesh faces: %ld\n", facenumber);
29431  if (meshedges > 0l) {
29432  printf(" Mesh edges: %ld\n", meshedges);
29433  } else {
29434  if (!nonconvex) {
29435  long vsize = points->items - dupverts - unuverts;
29436  if (b->weighted) vsize -= nonregularcount;
29437  meshedges = vsize + facenumber - tetnumber - 1;
29438  printf(" Mesh edges: %ld\n", meshedges);
29439  }
29440  }
29441 
29442  if (b->plc || b->refine) {
29443  printf(" Mesh faces on exterior boundary: %ld\n", hullsize);
29444  if (meshhulledges > 0l) {
29445  printf(" Mesh edges on exterior boundary: %ld\n", meshhulledges);
29446  }
29447  printf(" Mesh faces on input facets: %ld\n", subfaces->items);
29448  printf(" Mesh edges on input segments: %ld\n", subsegs->items);
29449  if (st_facref_count > 0l) {
29450  printf(" Steiner points on input facets: %ld\n", st_facref_count);
29451  }
29452  if (st_segref_count > 0l) {
29453  printf(" Steiner points on input segments: %ld\n", st_segref_count);
29454  }
29455  if (st_volref_count > 0l) {
29456  printf(" Steiner points inside domain: %ld\n", st_volref_count);
29457  }
29458  } else {
29459  printf(" Convex hull faces: %ld\n", hullsize);
29460  if (meshhulledges > 0l) {
29461  printf(" Convex hull edges: %ld\n", meshhulledges);
29462  }
29463  }
29464  if (b->weighted) { // -w option
29465  printf(" Skipped non-regular points: %ld\n", nonregularcount);
29466  }
29467  printf("\n");
29468 
29469 
29470  if (b->verbose > 0) {
29471  if (b->plc || b->refine) { // -p or -r
29472  if (tetrahedrons->items > 0l) {
29473  qualitystatistics();
29474  }
29475  }
29476  if (tetrahedrons->items > 0l) {
29477  memorystatistics();
29478  }
29479  }
29480 }
29481 
29485 
29489 
29491 // //
29492 // jettisonnodes() Jettison unused or duplicated vertices. //
29493 // //
29494 // Unused points are those input points which are outside the mesh domain or //
29495 // have no connection (isolated) to the mesh. Duplicated points exist for //
29496 // example if the input PLC is read from a .stl mesh file (marked during the //
29497 // Delaunay tetrahedralization step. This routine remove these points from //
29498 // points list. All existing points are reindexed. //
29499 // //
29501 
29502 void tetgenmesh::jettisonnodes()
29503 {
29504  point pointloop;
29505  bool jetflag;
29506  int oldidx, newidx;
29507  int remcount;
29508 
29509  if (!b->quiet) {
29510  printf("Jettisoning redundant points.\n");
29511  }
29512 
29513  points->traversalinit();
29514  pointloop = pointtraverse();
29515  oldidx = newidx = 0; // in->firstnumber;
29516  remcount = 0;
29517  while (pointloop != (point) NULL) {
29518  jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
29519  (pointtype(pointloop) == UNUSEDVERTEX);
29520  if (jetflag) {
29521  // It is a duplicated or unused point, delete it.
29522  pointdealloc(pointloop);
29523  remcount++;
29524  } else {
29525  // Re-index it.
29526  setpointmark(pointloop, newidx + in->firstnumber);
29527  if (in->pointmarkerlist != (int *) NULL) {
29528  if (oldidx < in->numberofpoints) {
29529  // Re-index the point marker as well.
29530  in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
29531  }
29532  }
29533  newidx++;
29534  }
29535  oldidx++;
29536  pointloop = pointtraverse();
29537  }
29538  if (b->verbose) {
29539  printf(" %ld duplicated vertices are removed.\n", dupverts);
29540  printf(" %ld unused vertices are removed.\n", unuverts);
29541  }
29542  dupverts = 0l;
29543  unuverts = 0l;
29544 
29545  // The following line ensures that dead items in the pool of nodes cannot
29546  // be allocated for the new created nodes. This ensures that the input
29547  // nodes will occur earlier in the output files, and have lower indices.
29548  points->deaditemstack = (void *) NULL;
29549 }
29550 
29552 // //
29553 // highorder() Create extra nodes for quadratic subparametric elements. //
29554 // //
29555 // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing //
29556 // high-order nodes of each tetrahedron. This routine is used only when -o2 //
29557 // switch is used. //
29558 // //
29560 
29561 void tetgenmesh::highorder()
29562 {
29563  triface tetloop, worktet, spintet;
29564  point *extralist, *adjextralist;
29565  point torg, tdest, newpoint;
29566  int highorderindex;
29567  int t1ver;
29568  int i, j;
29569 
29570  if (!b->quiet) {
29571  printf("Adding vertices for second-order tetrahedra.\n");
29572  }
29573 
29574  // Initialize the 'highordertable'.
29575  highordertable = new point[tetrahedrons->items * 6];
29576  if (highordertable == (point *) NULL) {
29577  terminatetetgen(this, 1);
29578  }
29579 
29580  // This will overwrite the slot for element markers.
29581  highorderindex = 11;
29582 
29583  // The following line ensures that dead items in the pool of nodes cannot
29584  // be allocated for the extra nodes associated with high order elements.
29585  // This ensures that the primary nodes (at the corners of elements) will
29586  // occur earlier in the output files, and have lower indices, than the
29587  // extra nodes.
29588  points->deaditemstack = (void *) NULL;
29589 
29590  // Assign an entry for each tetrahedron to find its extra nodes. At the
29591  // mean while, initialize all extra nodes be NULL.
29592  i = 0;
29593  tetrahedrons->traversalinit();
29594  tetloop.tet = tetrahedrontraverse();
29595  while (tetloop.tet != (tetrahedron *) NULL) {
29596  tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
29597  for (j = 0; j < 6; j++) {
29598  highordertable[i + j] = (point) NULL;
29599  }
29600  i += 6;
29601  tetloop.tet = tetrahedrontraverse();
29602  }
29603 
29604  // To create a unique node on each edge. Loop over all tetrahedra, and
29605  // look at the six edges of each tetrahedron. If the extra node in
29606  // the tetrahedron corresponding to this edge is NULL, create a node
29607  // for this edge, at the same time, set the new node into the extra
29608  // node lists of all other tetrahedra sharing this edge.
29609  tetrahedrons->traversalinit();
29610  tetloop.tet = tetrahedrontraverse();
29611  while (tetloop.tet != (tetrahedron *) NULL) {
29612  // Get the list of extra nodes.
29613  extralist = (point *) tetloop.tet[highorderindex];
29614  worktet.tet = tetloop.tet;
29615  for (i = 0; i < 6; i++) {
29616  if (extralist[i] == (point) NULL) {
29617  // Go to the ith-edge.
29618  worktet.ver = edge2ver[i];
29619  // Create a new point in the middle of this edge.
29620  torg = org(worktet);
29621  tdest = dest(worktet);
29622  makepoint(&newpoint, FREEVOLVERTEX);
29623  for (j = 0; j < 3 + numpointattrib; j++) {
29624  newpoint[j] = 0.5 * (torg[j] + tdest[j]);
29625  }
29626  // Interpolate its metrics.
29627  for (j = 0; j < in->numberofpointmtrs; j++) {
29628  newpoint[pointmtrindex + j] =
29629  0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
29630  }
29631  // Set this point into all extra node lists at this edge.
29632  spintet = worktet;
29633  while (1) {
29634  if (!ishulltet(spintet)) {
29635  adjextralist = (point *) spintet.tet[highorderindex];
29636  adjextralist[ver2edge[spintet.ver]] = newpoint;
29637  }
29638  fnextself(spintet);
29639  if (spintet.tet == worktet.tet) break;
29640  }
29641  } // if (!extralist[i])
29642  } // i
29643  tetloop.tet = tetrahedrontraverse();
29644  }
29645 }
29646 
29648 // //
29649 // indexelements() Index all tetrahedra. //
29650 // //
29651 // Many output functions require that the tetrahedra are indexed. This //
29652 // routine is called when -E option is used. //
29653 // //
29655 
29656 void tetgenmesh::indexelements()
29657 {
29658  triface worktet;
29659  int eindex = b->zeroindex ? 0 : in->firstnumber; // firstindex;
29660  tetrahedrons->traversalinit();
29661  worktet.tet = tetrahedrontraverse();
29662  while (worktet.tet != NULL) {
29663  setelemindex(worktet.tet, eindex);
29664  eindex++;
29665  if (b->metric) { // -m option
29666  // Update the point-to-tet map, so that every point is pointing
29667  // to a real tet, not a fictious one. Used by .p2t file.
29668  tetrahedron tptr = encode(worktet);
29669  for (int i = 0; i < 4; i++) {
29670  setpoint2tet((point) (worktet.tet[4 + i]), tptr);
29671  }
29672  }
29673  worktet.tet = tetrahedrontraverse();
29674  }
29675 }
29676 
29678 // //
29679 // numberedges() Count the number of edges, save in "meshedges". //
29680 // //
29681 // This routine is called when '-p' or '-r', and '-E' options are used. The //
29682 // total number of edges depends on the genus of the input surface mesh. //
29683 // //
29684 // NOTE: This routine must be called after outelements(). So all elements //
29685 // have been indexed. //
29686 // //
29688 
29689 void tetgenmesh::numberedges()
29690 {
29691  triface worktet, spintet;
29692  int ishulledge;
29693  int t1ver;
29694  int i;
29695 
29696  meshedges = meshhulledges = 0l;
29697 
29698  tetrahedrons->traversalinit();
29699  worktet.tet = tetrahedrontraverse();
29700  while (worktet.tet != NULL) {
29701  for (i = 0; i < 6; i++) {
29702  worktet.ver = edge2ver[i];
29703  ishulledge = 0;
29704  fnext(worktet, spintet);
29705  do {
29706  if (!ishulltet(spintet)) {
29707  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
29708  } else {
29709  ishulledge = 1;
29710  }
29711  fnextself(spintet);
29712  } while (spintet.tet != worktet.tet);
29713  if (spintet.tet == worktet.tet) {
29714  meshedges++;
29715  if (ishulledge) meshhulledges++;
29716  }
29717  }
29718  infect(worktet);
29719  worktet.tet = tetrahedrontraverse();
29720  }
29721 }
29722 
29724 // //
29725 // outnodes() Output the points to a .node file or a tetgenio structure. //
29726 // //
29727 // Note: each point has already been numbered on input (the first index is //
29728 // 'in->firstnumber'). //
29729 // //
29731 
29732 void tetgenmesh::outnodes(tetgenio* out)
29733 {
29734  FILE *outfile = NULL;
29735  char outnodefilename[FILENAMESIZE];
29736  face parentsh;
29737  point pointloop;
29738  int nextras, bmark, marker = 0, weightDT = 0;
29739  int coordindex, attribindex;
29740  int pointnumber, firstindex;
29741  int index, i;
29742 
29743  if (out == (tetgenio *) NULL) {
29744  strcpy(outnodefilename, b->outfilename);
29745  strcat(outnodefilename, ".node");
29746  }
29747 
29748  if (!b->quiet) {
29749  if (out == (tetgenio *) NULL) {
29750  printf("Writing %s.\n", outnodefilename);
29751  } else {
29752  printf("Writing nodes.\n");
29753  }
29754  }
29755 
29756  nextras = numpointattrib;
29757  if (b->weighted) { // -w
29758  if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
29759  }
29760 
29761  bmark = !b->nobound && in->pointmarkerlist;
29762 
29763  if (out == (tetgenio *) NULL) {
29764  outfile = fopen(outnodefilename, "w");
29765  if (outfile == (FILE *) NULL) {
29766  printf("File I/O Error: Cannot create file %s.\n", outnodefilename);
29767  terminatetetgen(this, 1);
29768  }
29769  // Number of points, number of dimensions, number of point attributes,
29770  // and number of boundary markers (zero or one).
29771  fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark);
29772  } else {
29773  // Allocate space for 'pointlist';
29774  out->pointlist = new REAL[points->items * 3];
29775  if (out->pointlist == (REAL *) NULL) {
29776  printf("Error: Out of memory.\n");
29777  terminatetetgen(this, 1);
29778  }
29779  // Allocate space for 'pointattributelist' if necessary;
29780  if (nextras > 0) {
29781  out->pointattributelist = new REAL[points->items * nextras];
29782  if (out->pointattributelist == (REAL *) NULL) {
29783  printf("Error: Out of memory.\n");
29784  terminatetetgen(this, 1);
29785  }
29786  }
29787  // Allocate space for 'pointmarkerlist' if necessary;
29788  if (bmark) {
29789  out->pointmarkerlist = new int[points->items];
29790  if (out->pointmarkerlist == (int *) NULL) {
29791  printf("Error: Out of memory.\n");
29792  terminatetetgen(this, 1);
29793  }
29794  }
29795  if (b->psc) {
29796  out->pointparamlist = new tetgenio::pointparam[points->items];
29797  if (out->pointparamlist == NULL) {
29798  printf("Error: Out of memory.\n");
29799  terminatetetgen(this, 1);
29800  }
29801  }
29802  out->numberofpoints = points->items;
29803  out->numberofpointattributes = nextras;
29804  coordindex = 0;
29805  attribindex = 0;
29806  }
29807 
29808  // Determine the first index (0 or 1).
29809  firstindex = b->zeroindex ? 0 : in->firstnumber;
29810 
29811  points->traversalinit();
29812  pointloop = pointtraverse();
29813  pointnumber = firstindex; // in->firstnumber;
29814  index = 0;
29815  while (pointloop != (point) NULL) {
29816  if (bmark) {
29817  // Default the vertex has a zero marker.
29818  marker = 0;
29819  // Is it an input vertex?
29820  if (index < in->numberofpoints) {
29821  // Input point's marker is directly copied to output.
29822  marker = in->pointmarkerlist[index];
29823  } else {
29824  if ((pointtype(pointloop) == FREESEGVERTEX) ||
29825  (pointtype(pointloop) == FREEFACETVERTEX)) {
29826  sdecode(point2sh(pointloop), parentsh);
29827  if (parentsh.sh != NULL) {
29828  marker = shellmark(parentsh);
29829  }
29830  } // if (pointtype(...))
29831  }
29832  }
29833  if (out == (tetgenio *) NULL) {
29834  // Point number, x, y and z coordinates.
29835  fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
29836  pointloop[0], pointloop[1], pointloop[2]);
29837  for (i = 0; i < nextras; i++) {
29838  // Write an attribute.
29839  if ((i == 0) && weightDT) {
29840  fprintf(outfile, " %.17g", pointloop[0] * pointloop[0] +
29841  pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2]
29842  - pointloop[3 + i]);
29843  } else {
29844  fprintf(outfile, " %.17g", pointloop[3 + i]);
29845  }
29846  }
29847  if (bmark) {
29848  // Write the boundary marker.
29849  fprintf(outfile, " %d", marker);
29850  }
29851  if (b->psc) {
29852  fprintf(outfile, " %.8g %.8g %d", pointgeomuv(pointloop, 0),
29853  pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
29854  if (pointtype(pointloop) == RIDGEVERTEX) {
29855  fprintf(outfile, " 0");
29856  } else if (pointtype(pointloop) == ACUTEVERTEX) {
29857  fprintf(outfile, " 0");
29858  } else if (pointtype(pointloop) == FREESEGVERTEX) {
29859  fprintf(outfile, " 1");
29860  } else if (pointtype(pointloop) == FREEFACETVERTEX) {
29861  fprintf(outfile, " 2");
29862  } else if (pointtype(pointloop) == FREEVOLVERTEX) {
29863  fprintf(outfile, " 3");
29864  } else {
29865  fprintf(outfile, " -1"); // Unknown type.
29866  }
29867  }
29868  fprintf(outfile, "\n");
29869  } else {
29870  // X, y, and z coordinates.
29871  out->pointlist[coordindex++] = pointloop[0];
29872  out->pointlist[coordindex++] = pointloop[1];
29873  out->pointlist[coordindex++] = pointloop[2];
29874  // Point attributes.
29875  for (i = 0; i < nextras; i++) {
29876  // Output an attribute.
29877  if ((i == 0) && weightDT) {
29878  out->pointattributelist[attribindex++] =
29879  pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] +
29880  pointloop[2] * pointloop[2] - pointloop[3 + i];
29881  } else {
29882  out->pointattributelist[attribindex++] = pointloop[3 + i];
29883  }
29884  }
29885  if (bmark) {
29886  // Output the boundary marker.
29887  out->pointmarkerlist[index] = marker;
29888  }
29889  if (b->psc) {
29890  out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
29891  out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
29892  out->pointparamlist[index].tag = pointgeomtag(pointloop);
29893  if (pointtype(pointloop) == RIDGEVERTEX) {
29894  out->pointparamlist[index].type = 0;
29895  } else if (pointtype(pointloop) == ACUTEVERTEX) {
29896  out->pointparamlist[index].type = 0;
29897  } else if (pointtype(pointloop) == FREESEGVERTEX) {
29898  out->pointparamlist[index].type = 1;
29899  } else if (pointtype(pointloop) == FREEFACETVERTEX) {
29900  out->pointparamlist[index].type = 2;
29901  } else if (pointtype(pointloop) == FREEVOLVERTEX) {
29902  out->pointparamlist[index].type = 3;
29903  } else {
29904  out->pointparamlist[index].type = -1; // Unknown type.
29905  }
29906  }
29907  }
29908  pointloop = pointtraverse();
29909  pointnumber++;
29910  index++;
29911  }
29912 
29913  if (out == (tetgenio *) NULL) {
29914  fprintf(outfile, "# Generated by %s\n", b->commandline);
29915  fclose(outfile);
29916  }
29917 }
29918 
29920 // //
29921 // outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. //
29922 // //
29924 
29925 void tetgenmesh::outmetrics(tetgenio* out)
29926 {
29927  FILE *outfile = NULL;
29928  char outmtrfilename[FILENAMESIZE];
29929  point ptloop;
29930  int mtrindex = 0;
29931  int i;
29932  int msize = (sizeoftensor - useinsertradius);
29933  if (msize == 0) {
29934  return;
29935  }
29936 
29937  if (out == (tetgenio *) NULL) {
29938  strcpy(outmtrfilename, b->outfilename);
29939  strcat(outmtrfilename, ".mtr");
29940  }
29941 
29942  if (!b->quiet) {
29943  if (out == (tetgenio *) NULL) {
29944  printf("Writing %s.\n", outmtrfilename);
29945  } else {
29946  printf("Writing metrics.\n");
29947  }
29948  }
29949 
29950  if (out == (tetgenio *) NULL) {
29951  outfile = fopen(outmtrfilename, "w");
29952  if (outfile == (FILE *) NULL) {
29953  printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
29954  terminatetetgen(this, 3);
29955  }
29956  // Number of points, number of point metrices,
29957  fprintf(outfile, "%ld %d\n", points->items, msize);
29958  } else {
29959  // Allocate space for 'pointmtrlist'.
29960  out->numberofpointmtrs = msize;
29961  out->pointmtrlist = new REAL[points->items * msize];
29962  if (out->pointmtrlist == (REAL *) NULL) {
29963  terminatetetgen(this, 1);
29964  }
29965  }
29966 
29967  points->traversalinit();
29968  ptloop = pointtraverse();
29969  while (ptloop != (point) NULL) {
29970  if (out == (tetgenio *) NULL) {
29971  for (i = 0; i < msize; i++) {
29972  fprintf(outfile, " %-16.8e", ptloop[pointmtrindex + i]);
29973  }
29974  fprintf(outfile, "\n");
29975  } else {
29976  for (i = 0; i < msize; i++) {
29977  out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
29978  }
29979  }
29980  ptloop = pointtraverse();
29981  }
29982 
29983  // Output the point-to-tet map.
29984  if (out == (tetgenio *) NULL) {
29985  strcpy(outmtrfilename, b->outfilename);
29986  strcat(outmtrfilename, ".p2t");
29987  }
29988 
29989  if (!b->quiet) {
29990  if (out == (tetgenio *) NULL) {
29991  printf("Writing %s.\n", outmtrfilename);
29992  } else {
29993  printf("Writing point-to-tet map.\n");
29994  }
29995  }
29996 
29997  if (out == (tetgenio *) NULL) {
29998  outfile = fopen(outmtrfilename, "w");
29999  if (outfile == (FILE *) NULL) {
30000  printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
30001  terminatetetgen(this, 3);
30002  }
30003  // Number of points,
30004  //fprintf(outfile, "%ld\n", points->items);
30005  } else {
30006  // Allocate space for 'point2tetlist'.
30007  out->point2tetlist = new int[points->items];
30008  if (out->point2tetlist == (int *) NULL) {
30009  terminatetetgen(this, 1);
30010  }
30011  }
30012 
30013  // The list of tetrahedra must be indexed.
30014  if (bgm != NULL) {
30015  bgm->indexelements();
30016  }
30017  // Determine the first index (0 or 1).
30018  int firstindex = b->zeroindex ? 0 : in->firstnumber;
30019  int pointindex = firstindex;
30020  i = 0;
30021 
30022  triface parenttet;
30023  points->traversalinit();
30024  ptloop = pointtraverse();
30025  while (ptloop != (point) NULL) {
30026  if (bgm != NULL) {
30027  bgm->decode(point2bgmtet(ptloop), parenttet);
30028  } else {
30029  decode(point2tet(ptloop), parenttet);
30030  }
30031  if (out == (tetgenio *) NULL) {
30032  fprintf(outfile, "%d %d\n", pointindex, elemindex(parenttet.tet));
30033  } else {
30034  out->point2tetlist[i] = elemindex(parenttet.tet);
30035  }
30036  pointindex++;
30037  i++;
30038  ptloop = pointtraverse();
30039  }
30040 
30041  if (out == (tetgenio *) NULL) {
30042  fprintf(outfile, "# Generated by %s\n", b->commandline);
30043  fclose(outfile);
30044  }
30045 }
30046 
30048 // //
30049 // outelements() Output the tetrahedra to an .ele file or a tetgenio //
30050 // structure. //
30051 // //
30052 // This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
30053 // firstnumber). The total number of mesh edges is counted in 'meshedges'. //
30054 // //
30056 
30057 void tetgenmesh::outelements(tetgenio* out)
30058 {
30059  FILE *outfile = NULL;
30060  char outelefilename[FILENAMESIZE];
30061  tetrahedron* tptr;
30062  point p1, p2, p3, p4;
30063  point *extralist;
30064  REAL *talist = NULL;
30065  int *tlist = NULL;
30066  long ntets;
30067  int firstindex, shift;
30068  int pointindex, attribindex;
30069  int highorderindex = 11;
30070  int elementnumber;
30071  int eextras;
30072  int i;
30073 
30074  if (out == (tetgenio *) NULL) {
30075  strcpy(outelefilename, b->outfilename);
30076  strcat(outelefilename, ".ele");
30077  }
30078 
30079  if (!b->quiet) {
30080  if (out == (tetgenio *) NULL) {
30081  printf("Writing %s.\n", outelefilename);
30082  } else {
30083  printf("Writing elements.\n");
30084  }
30085  }
30086 
30087  // The number of tets excluding hull tets.
30088  ntets = tetrahedrons->items - hullsize;
30089 
30090  eextras = numelemattrib;
30091  if (out == (tetgenio *) NULL) {
30092  outfile = fopen(outelefilename, "w");
30093  if (outfile == (FILE *) NULL) {
30094  printf("File I/O Error: Cannot create file %s.\n", outelefilename);
30095  terminatetetgen(this, 1);
30096  }
30097  // Number of tetras, points per tetra, attributes per tetra.
30098  fprintf(outfile, "%ld %d %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
30099  } else {
30100  // Allocate memory for output tetrahedra.
30101  out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
30102  if (out->tetrahedronlist == (int *) NULL) {
30103  printf("Error: Out of memory.\n");
30104  terminatetetgen(this, 1);
30105  }
30106  // Allocate memory for output tetrahedron attributes if necessary.
30107  if (eextras > 0) {
30108  out->tetrahedronattributelist = new REAL[ntets * eextras];
30109  if (out->tetrahedronattributelist == (REAL *) NULL) {
30110  printf("Error: Out of memory.\n");
30111  terminatetetgen(this, 1);
30112  }
30113  }
30114  out->numberoftetrahedra = ntets;
30115  out->numberofcorners = b->order == 1 ? 4 : 10;
30116  out->numberoftetrahedronattributes = eextras;
30117  tlist = out->tetrahedronlist;
30118  talist = out->tetrahedronattributelist;
30119  pointindex = 0;
30120  attribindex = 0;
30121  }
30122 
30123  // Determine the first index (0 or 1).
30124  firstindex = b->zeroindex ? 0 : in->firstnumber;
30125  shift = 0; // Default no shift.
30126  if ((in->firstnumber == 1) && (firstindex == 0)) {
30127  shift = 1; // Shift the output indices by 1.
30128  }
30129 
30130  tetrahedrons->traversalinit();
30131  tptr = tetrahedrontraverse();
30132  elementnumber = firstindex; // in->firstnumber;
30133  while (tptr != (tetrahedron *) NULL) {
30134  if (!b->reversetetori) {
30135  p1 = (point) tptr[4];
30136  p2 = (point) tptr[5];
30137  } else {
30138  p1 = (point) tptr[5];
30139  p2 = (point) tptr[4];
30140  }
30141  p3 = (point) tptr[6];
30142  p4 = (point) tptr[7];
30143  if (out == (tetgenio *) NULL) {
30144  // Tetrahedron number, indices for four points.
30145  fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
30146  pointmark(p1) - shift, pointmark(p2) - shift,
30147  pointmark(p3) - shift, pointmark(p4) - shift);
30148  if (b->order == 2) {
30149  extralist = (point *) tptr[highorderindex];
30150  // indices for six extra points.
30151  fprintf(outfile, " %5d %5d %5d %5d %5d %5d",
30152  pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
30153  pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
30154  pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
30155  }
30156  for (i = 0; i < eextras; i++) {
30157  fprintf(outfile, " %.17g", elemattribute(tptr, i));
30158  }
30159  fprintf(outfile, "\n");
30160  } else {
30161  tlist[pointindex++] = pointmark(p1) - shift;
30162  tlist[pointindex++] = pointmark(p2) - shift;
30163  tlist[pointindex++] = pointmark(p3) - shift;
30164  tlist[pointindex++] = pointmark(p4) - shift;
30165  if (b->order == 2) {
30166  extralist = (point *) tptr[highorderindex];
30167  tlist[pointindex++] = pointmark(extralist[0]) - shift;
30168  tlist[pointindex++] = pointmark(extralist[1]) - shift;
30169  tlist[pointindex++] = pointmark(extralist[2]) - shift;
30170  tlist[pointindex++] = pointmark(extralist[3]) - shift;
30171  tlist[pointindex++] = pointmark(extralist[4]) - shift;
30172  tlist[pointindex++] = pointmark(extralist[5]) - shift;
30173  }
30174  for (i = 0; i < eextras; i++) {
30175  talist[attribindex++] = elemattribute(tptr, i);
30176  }
30177  }
30178  // Remember the index of this element (for counting edges).
30179  setelemindex(tptr, elementnumber);
30180  if (b->metric) { // -m option
30181  // Update the point-to-tet map, so that every point is pointing
30182  // to a real tet, not a fictious one. Used by .p2t file.
30183  for (int i = 0; i < 4; i++) {
30184  setpoint2tet((point) (tptr[4 + i]), (tetrahedron) tptr);
30185  }
30186  }
30187  tptr = tetrahedrontraverse();
30188  elementnumber++;
30189  }
30190 
30191 
30192  if (out == (tetgenio *) NULL) {
30193  fprintf(outfile, "# Generated by %s\n", b->commandline);
30194  fclose(outfile);
30195  }
30196 }
30197 
30199 // //
30200 // outfaces() Output all faces to a .face file or a tetgenio object. //
30201 // //
30203 
30204 void tetgenmesh::outfaces(tetgenio* out)
30205 {
30206  FILE *outfile = NULL;
30207  char facefilename[FILENAMESIZE];
30208  triface tface, tsymface;
30209  face checkmark;
30210  point torg, tdest, tapex;
30211  long ntets, faces;
30212  int *elist = NULL, *emlist = NULL;
30213  int neigh1 = 0, neigh2 = 0;
30214  int marker = 0;
30215  int firstindex, shift;
30216  int facenumber;
30217  int index = 0;
30218 
30219  // For -o2 option.
30220  triface workface;
30221  point *extralist, pp[3] = {0,0,0};
30222  int highorderindex = 11;
30223  int o2index = 0, i;
30224 
30225  // For -nn option.
30226  int *tet2facelist = NULL;
30227  int tidx;
30228 
30229  if (out == (tetgenio *) NULL) {
30230  strcpy(facefilename, b->outfilename);
30231  strcat(facefilename, ".face");
30232  }
30233 
30234  if (!b->quiet) {
30235  if (out == (tetgenio *) NULL) {
30236  printf("Writing %s.\n", facefilename);
30237  } else {
30238  printf("Writing faces.\n");
30239  }
30240  }
30241 
30242  ntets = tetrahedrons->items - hullsize;
30243  faces = (ntets * 4l + hullsize) / 2l;
30244 
30245  if (out == (tetgenio *) NULL) {
30246  outfile = fopen(facefilename, "w");
30247  if (outfile == (FILE *) NULL) {
30248  printf("File I/O Error: Cannot create file %s.\n", facefilename);
30249  terminatetetgen(this, 1);
30250  }
30251  fprintf(outfile, "%ld %d\n", faces, !b->nobound);
30252  } else {
30253  // Allocate memory for 'trifacelist'.
30254  out->trifacelist = new int[faces * 3];
30255  if (out->trifacelist == (int *) NULL) {
30256  printf("Error: Out of memory.\n");
30257  terminatetetgen(this, 1);
30258  }
30259  if (b->order == 2) {
30260  out->o2facelist = new int[faces * 3];
30261  }
30262  // Allocate memory for 'trifacemarkerlist' if necessary.
30263  if (!b->nobound) {
30264  out->trifacemarkerlist = new int[faces];
30265  if (out->trifacemarkerlist == (int *) NULL) {
30266  printf("Error: Out of memory.\n");
30267  terminatetetgen(this, 1);
30268  }
30269  }
30270  if (b->neighout > 1) {
30271  // '-nn' switch.
30272  out->face2tetlist = new int[faces * 2];
30273  if (out->face2tetlist == (int *) NULL) {
30274  printf("Error: Out of memory.\n");
30275  terminatetetgen(this, 1);
30276  }
30277  }
30278  out->numberoftrifaces = faces;
30279  elist = out->trifacelist;
30280  emlist = out->trifacemarkerlist;
30281  }
30282 
30283  if (b->neighout > 1) { // -nn option
30284  // Output the tetrahedron-to-face map.
30285  tet2facelist = new int[ntets * 4];
30286  }
30287 
30288  // Determine the first index (0 or 1).
30289  firstindex = b->zeroindex ? 0 : in->firstnumber;
30290  shift = 0; // Default no shiftment.
30291  if ((in->firstnumber == 1) && (firstindex == 0)) {
30292  shift = 1; // Shift the output indices by 1.
30293  }
30294 
30295  tetrahedrons->traversalinit();
30296  tface.tet = tetrahedrontraverse();
30297  facenumber = firstindex; // in->firstnumber;
30298  // To loop over the set of faces, loop over all tetrahedra, and look at
30299  // the four faces of each one. If its adjacent tet is a hull tet,
30300  // operate on the face, otherwise, operate on the face only if the
30301  // current tet has a smaller index than its neighbor.
30302  while (tface.tet != (tetrahedron *) NULL) {
30303  for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
30304  fsym(tface, tsymface);
30305  if (ishulltet(tsymface) ||
30306  (elemindex(tface.tet) < elemindex(tsymface.tet))) {
30307  torg = org(tface);
30308  tdest = dest(tface);
30309  tapex = apex(tface);
30310  if (b->order == 2) { // -o2
30311  // Get the three extra vertices on edges.
30312  extralist = (point *) (tface.tet[highorderindex]);
30313  // The extra vertices are on edges opposite the corners.
30314  enext(tface, workface);
30315  for (i = 0; i < 3; i++) {
30316  pp[i] = extralist[ver2edge[workface.ver]];
30317  enextself(workface);
30318  }
30319  }
30320  if (!b->nobound) {
30321  // Get the boundary marker of this face.
30322  if (b->plc || b->refine) {
30323  // Shell face is used.
30324  tspivot(tface, checkmark);
30325  if (checkmark.sh == NULL) {
30326  marker = 0; // It is an inner face. It's marker is 0.
30327  } else {
30328  marker = shellmark(checkmark);
30329  }
30330  } else {
30331  // Shell face is not used, only distinguish outer and inner face.
30332  marker = (int) ishulltet(tsymface);
30333  }
30334  }
30335  if (b->neighout > 1) {
30336  // '-nn' switch. Output adjacent tets indices.
30337  if (!ishulltet(tface)) {
30338  neigh1 = elemindex(tface.tet);
30339  } else {
30340  neigh1 = -1;
30341  }
30342  if (!ishulltet(tsymface)) {
30343  neigh2 = elemindex(tsymface.tet);
30344  } else {
30345  neigh2 = -1;
30346  }
30347  // Fill the tetrahedron-to-face map.
30348  tidx = elemindex(tface.tet) - firstindex;
30349  tet2facelist[tidx * 4 + tface.ver] = facenumber;
30350  if (!ishulltet(tsymface)) {
30351  tidx = elemindex(tsymface.tet) - firstindex;
30352  tet2facelist[tidx * 4 + (tsymface.ver & 3)] = facenumber;
30353  }
30354  }
30355  if (out == (tetgenio *) NULL) {
30356  // Face number, indices of three vertices.
30357  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
30358  pointmark(torg) - shift, pointmark(tdest) - shift,
30359  pointmark(tapex) - shift);
30360  if (b->order == 2) { // -o2
30361  fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
30362  pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
30363  }
30364  if (!b->nobound) {
30365  // Output a boundary marker.
30366  fprintf(outfile, " %d", marker);
30367  }
30368  if (b->neighout > 1) {
30369  fprintf(outfile, " %5d %5d", neigh1, neigh2);
30370  }
30371  fprintf(outfile, "\n");
30372  } else {
30373  // Output indices of three vertices.
30374  elist[index++] = pointmark(torg) - shift;
30375  elist[index++] = pointmark(tdest) - shift;
30376  elist[index++] = pointmark(tapex) - shift;
30377  if (b->order == 2) { // -o2
30378  out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
30379  out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
30380  out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
30381  }
30382  if (!b->nobound) {
30383  emlist[facenumber - in->firstnumber] = marker;
30384  }
30385  if (b->neighout > 1) {
30386  out->face2tetlist[(facenumber - in->firstnumber) * 2] = neigh1;
30387  out->face2tetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
30388  }
30389  }
30390  facenumber++;
30391  }
30392  }
30393  tface.tet = tetrahedrontraverse();
30394  }
30395 
30396  if (out == (tetgenio *) NULL) {
30397  fprintf(outfile, "# Generated by %s\n", b->commandline);
30398  fclose(outfile);
30399  }
30400 
30401  if (b->neighout > 1) { // -nn option
30402  // Output the tetrahedron-to-face map.
30403  if (out == (tetgenio *) NULL) {
30404  strcpy(facefilename, b->outfilename);
30405  strcat(facefilename, ".t2f");
30406  }
30407  if (!b->quiet) {
30408  if (out == (tetgenio *) NULL) {
30409  printf("Writing %s.\n", facefilename);
30410  } else {
30411  printf("Writing tetrahedron-to-face map.\n");
30412  }
30413  }
30414  if (out == (tetgenio *) NULL) {
30415  outfile = fopen(facefilename, "w");
30416  for (tidx = 0; tidx < ntets; tidx++) {
30417  index = tidx * 4;
30418  fprintf(outfile, "%4d %d %d %d %d\n", tidx + in->firstnumber,
30419  tet2facelist[index], tet2facelist[index+1],
30420  tet2facelist[index+2], tet2facelist[index+3]);
30421  }
30422  fclose(outfile);
30423  delete [] tet2facelist;
30424  } else {
30425  // Simply copy the address of the list to the output.
30426  out->tet2facelist = tet2facelist;
30427  }
30428  }
30429 }
30430 
30432 // //
30433 // outhullfaces() Output hull faces to a .face file or a tetgenio object. //
30434 // //
30435 // The normal of each face is pointing to the outside of the domain. //
30436 // //
30438 
30439 void tetgenmesh::outhullfaces(tetgenio* out)
30440 {
30441  FILE *outfile = NULL;
30442  char facefilename[FILENAMESIZE];
30443  triface hulltet;
30444  point torg, tdest, tapex;
30445  int *elist = NULL;
30446  int firstindex, shift;
30447  int facenumber;
30448  int index;
30449 
30450  if (out == (tetgenio *) NULL) {
30451  strcpy(facefilename, b->outfilename);
30452  strcat(facefilename, ".face");
30453  }
30454 
30455  if (!b->quiet) {
30456  if (out == (tetgenio *) NULL) {
30457  printf("Writing %s.\n", facefilename);
30458  } else {
30459  printf("Writing faces.\n");
30460  }
30461  }
30462 
30463  if (out == (tetgenio *) NULL) {
30464  outfile = fopen(facefilename, "w");
30465  if (outfile == (FILE *) NULL) {
30466  printf("File I/O Error: Cannot create file %s.\n", facefilename);
30467  terminatetetgen(this, 1);
30468  }
30469  fprintf(outfile, "%ld 0\n", hullsize);
30470  } else {
30471  // Allocate memory for 'trifacelist'.
30472  out->trifacelist = new int[hullsize * 3];
30473  if (out->trifacelist == (int *) NULL) {
30474  printf("Error: Out of memory.\n");
30475  terminatetetgen(this, 1);
30476  }
30477  out->numberoftrifaces = hullsize;
30478  elist = out->trifacelist;
30479  index = 0;
30480  }
30481 
30482  // Determine the first index (0 or 1).
30483  firstindex = b->zeroindex ? 0 : in->firstnumber;
30484  shift = 0; // Default no shiftment.
30485  if ((in->firstnumber == 1) && (firstindex == 0)) {
30486  shift = 1; // Shift the output indices by 1.
30487  }
30488 
30489  tetrahedrons->traversalinit();
30490  hulltet.tet = alltetrahedrontraverse();
30491  facenumber = firstindex;
30492  while (hulltet.tet != (tetrahedron *) NULL) {
30493  if (ishulltet(hulltet)) {
30494  torg = (point) hulltet.tet[4];
30495  tdest = (point) hulltet.tet[5];
30496  tapex = (point) hulltet.tet[6];
30497  if (out == (tetgenio *) NULL) {
30498  // Face number, indices of three vertices.
30499  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
30500  pointmark(torg) - shift, pointmark(tdest) - shift,
30501  pointmark(tapex) - shift);
30502  fprintf(outfile, "\n");
30503  } else {
30504  // Output indices of three vertices.
30505  elist[index++] = pointmark(torg) - shift;
30506  elist[index++] = pointmark(tdest) - shift;
30507  elist[index++] = pointmark(tapex) - shift;
30508  }
30509  facenumber++;
30510  }
30511  hulltet.tet = alltetrahedrontraverse();
30512  }
30513 
30514  if (out == (tetgenio *) NULL) {
30515  fprintf(outfile, "# Generated by %s\n", b->commandline);
30516  fclose(outfile);
30517  }
30518 }
30519 
30521 // //
30522 // outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or //
30523 // a tetgenio structure. //
30524 // //
30525 // The boundary faces are found in 'subfaces'. For listing triangle vertices //
30526 // in the same sense for all triangles in the mesh, the direction determined //
30527 // by right-hand rule is pointer to the inside of the volume. //
30528 // //
30530 
30531 void tetgenmesh::outsubfaces(tetgenio* out)
30532 {
30533  FILE *outfile = NULL;
30534  char facefilename[FILENAMESIZE];
30535  int *elist = NULL;
30536  int *emlist = NULL;
30537  int index = 0, index1 = 0, index2 = 0;
30538  triface abuttingtet;
30539  face faceloop;
30540  point torg, tdest, tapex;
30541  int marker = 0;
30542  int firstindex, shift;
30543  int neigh1 = 0, neigh2 = 0;
30544  int facenumber;
30545 
30546  // For -o2 option.
30547  triface workface;
30548  point *extralist, pp[3] = {0,0,0};
30549  int highorderindex = 11;
30550  int o2index = 0, i;
30551 
30552  int t1ver; // used by fsymself()
30553 
30554  if (out == (tetgenio *) NULL) {
30555  strcpy(facefilename, b->outfilename);
30556  strcat(facefilename, ".face");
30557  }
30558 
30559  if (!b->quiet) {
30560  if (out == (tetgenio *) NULL) {
30561  printf("Writing %s.\n", facefilename);
30562  } else {
30563  printf("Writing faces.\n");
30564  }
30565  }
30566 
30567  if (out == (tetgenio *) NULL) {
30568  outfile = fopen(facefilename, "w");
30569  if (outfile == (FILE *) NULL) {
30570  printf("File I/O Error: Cannot create file %s.\n", facefilename);
30571  terminatetetgen(this, 3);
30572  }
30573  // Number of subfaces.
30574  fprintf(outfile, "%ld %d\n", subfaces->items, !b->nobound);
30575  } else {
30576  // Allocate memory for 'trifacelist'.
30577  out->trifacelist = new int[subfaces->items * 3];
30578  if (out->trifacelist == (int *) NULL) {
30579  terminatetetgen(this, 1);
30580  }
30581  if (b->order == 2) {
30582  out->o2facelist = new int[subfaces->items * 3];
30583  }
30584  if (!b->nobound) {
30585  // Allocate memory for 'trifacemarkerlist'.
30586  out->trifacemarkerlist = new int[subfaces->items];
30587  if (out->trifacemarkerlist == (int *) NULL) {
30588  terminatetetgen(this, 1);
30589  }
30590  }
30591  if (b->neighout > 1) {
30592  // '-nn' switch.
30593  out->face2tetlist = new int[subfaces->items * 2];
30594  if (out->face2tetlist == (int *) NULL) {
30595  terminatetetgen(this, 1);
30596  }
30597  }
30598  out->numberoftrifaces = subfaces->items;
30599  elist = out->trifacelist;
30600  emlist = out->trifacemarkerlist;
30601  }
30602 
30603  // Determine the first index (0 or 1).
30604  firstindex = b->zeroindex ? 0 : in->firstnumber;
30605  shift = 0; // Default no shiftment.
30606  if ((in->firstnumber == 1) && (firstindex == 0)) {
30607  shift = 1; // Shift the output indices by 1.
30608  }
30609 
30610  subfaces->traversalinit();
30611  faceloop.sh = shellfacetraverse(subfaces);
30612  facenumber = firstindex; // in->firstnumber;
30613  while (faceloop.sh != (shellface *) NULL) {
30614  stpivot(faceloop, abuttingtet);
30615  // If there is a tetrahedron containing this subface, orient it so
30616  // that the normal of this face points to inside of the volume by
30617  // right-hand rule.
30618  if (abuttingtet.tet != NULL) {
30619  if (ishulltet(abuttingtet)) {
30620  fsymself(abuttingtet);
30621  }
30622  }
30623  if (abuttingtet.tet != NULL) {
30624  torg = org(abuttingtet);
30625  tdest = dest(abuttingtet);
30626  tapex = apex(abuttingtet);
30627  if (b->order == 2) { // -o2
30628  // Get the three extra vertices on edges.
30629  extralist = (point *) (abuttingtet.tet[highorderindex]);
30630  workface = abuttingtet;
30631  for (i = 0; i < 3; i++) {
30632  pp[i] = extralist[ver2edge[workface.ver]];
30633  enextself(workface);
30634  }
30635  }
30636  } else {
30637  // This may happen when only a surface mesh be generated.
30638  torg = sorg(faceloop);
30639  tdest = sdest(faceloop);
30640  tapex = sapex(faceloop);
30641  if (b->order == 2) { // -o2
30642  // There is no extra node list available.
30643  pp[0] = torg;
30644  pp[1] = tdest;
30645  pp[2] = tapex;
30646  }
30647  }
30648  if (!b->nobound) {
30649  marker = shellmark(faceloop);
30650  }
30651  if (b->neighout > 1) {
30652  // '-nn' switch. Output adjacent tets indices.
30653  neigh1 = -1;
30654  neigh2 = -1;
30655  stpivot(faceloop, abuttingtet);
30656  if (abuttingtet.tet != NULL) {
30657  if (!ishulltet(abuttingtet)) {
30658  neigh1 = elemindex(abuttingtet.tet);
30659  }
30660  fsymself(abuttingtet);
30661  if (!ishulltet(abuttingtet)) {
30662  neigh2 = elemindex(abuttingtet.tet);
30663  }
30664  }
30665  }
30666  if (out == (tetgenio *) NULL) {
30667  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
30668  pointmark(torg) - shift, pointmark(tdest) - shift,
30669  pointmark(tapex) - shift);
30670  if (b->order == 2) { // -o2
30671  fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
30672  pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
30673  }
30674  if (!b->nobound) {
30675  fprintf(outfile, " %d", marker);
30676  }
30677  if (b->neighout > 1) {
30678  fprintf(outfile, " %5d %5d", neigh1, neigh2);
30679  }
30680  fprintf(outfile, "\n");
30681  } else {
30682  // Output three vertices of this face;
30683  elist[index++] = pointmark(torg) - shift;
30684  elist[index++] = pointmark(tdest) - shift;
30685  elist[index++] = pointmark(tapex) - shift;
30686  if (b->order == 2) { // -o2
30687  out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
30688  out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
30689  out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
30690  }
30691  if (!b->nobound) {
30692  emlist[index1++] = marker;
30693  }
30694  if (b->neighout > 1) {
30695  out->face2tetlist[index2++] = neigh1;
30696  out->face2tetlist[index2++] = neigh2;
30697  }
30698  }
30699  facenumber++;
30700  faceloop.sh = shellfacetraverse(subfaces);
30701  }
30702 
30703  if (out == (tetgenio *) NULL) {
30704  fprintf(outfile, "# Generated by %s\n", b->commandline);
30705  fclose(outfile);
30706  }
30707 }
30708 
30710 // //
30711 // outedges() Output all edges to a .edge file or a tetgenio object. //
30712 // //
30713 // Note: This routine must be called after outelements(), so that the total //
30714 // number of edges 'meshedges' has been counted. //
30715 // //
30717 
30718 void tetgenmesh::outedges(tetgenio* out)
30719 {
30720  FILE *outfile = NULL;
30721  char edgefilename[FILENAMESIZE];
30722  triface tetloop, worktet, spintet;
30723  face checkseg;
30724  point torg, tdest;
30725  int ishulledge;
30726  int firstindex, shift;
30727  int edgenumber, marker;
30728  int index = 0, index1 = 0, index2 = 0;
30729  int t1ver;
30730  int i;
30731 
30732  // For -o2 option.
30733  point *extralist, pp = NULL;
30734  int highorderindex = 11;
30735  int o2index = 0;
30736 
30737  // For -nn option.
30738  int *tet2edgelist = NULL;
30739  int tidx;
30740 
30741  if (out == (tetgenio *) NULL) {
30742  strcpy(edgefilename, b->outfilename);
30743  strcat(edgefilename, ".edge");
30744  }
30745 
30746  if (!b->quiet) {
30747  if (out == (tetgenio *) NULL) {
30748  printf("Writing %s.\n", edgefilename);
30749  } else {
30750  printf("Writing edges.\n");
30751  }
30752  }
30753 
30754  if (meshedges == 0l) {
30755  if (nonconvex) {
30756  numberedges(); // Count the edges.
30757  } else {
30758  // Use Euler's characteristic to get the numbe of edges.
30759  // It states V - E + F - C = 1, hence E = V + F - C - 1.
30760  long tsize = tetrahedrons->items - hullsize;
30761  long fsize = (tsize * 4l + hullsize) / 2l;
30762  long vsize = points->items - dupverts - unuverts;
30763  if (b->weighted) vsize -= nonregularcount;
30764  meshedges = vsize + fsize - tsize - 1;
30765  }
30766  }
30767  meshhulledges = 0l; // It will be counted.
30768 
30769  if (out == (tetgenio *) NULL) {
30770  outfile = fopen(edgefilename, "w");
30771  if (outfile == (FILE *) NULL) {
30772  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
30773  terminatetetgen(this, 1);
30774  }
30775  // Write the number of edges, boundary markers (0 or 1).
30776  fprintf(outfile, "%ld %d\n", meshedges, !b->nobound);
30777  } else {
30778  // Allocate memory for 'edgelist'.
30779  out->numberofedges = meshedges;
30780  out->edgelist = new int[meshedges * 2];
30781  if (out->edgelist == (int *) NULL) {
30782  printf("Error: Out of memory.\n");
30783  terminatetetgen(this, 1);
30784  }
30785  if (b->order == 2) { // -o2 switch
30786  out->o2edgelist = new int[meshedges];
30787  }
30788  if (!b->nobound) {
30789  out->edgemarkerlist = new int[meshedges];
30790  }
30791  if (b->neighout > 1) { // '-nn' switch.
30792  out->edge2tetlist = new int[meshedges];
30793  }
30794  }
30795 
30796  if (b->neighout > 1) { // -nn option
30797  // Output the tetrahedron-to-edge map.
30798  long tsize = tetrahedrons->items - hullsize;
30799  tet2edgelist = new int[tsize * 6];
30800  }
30801 
30802  // Determine the first index (0 or 1).
30803  firstindex = b->zeroindex ? 0 : in->firstnumber;
30804  shift = 0; // Default no shiftment.
30805  if ((in->firstnumber == 1) && (firstindex == 0)) {
30806  shift = 1; // Shift (reduce) the output indices by 1.
30807  }
30808 
30809  tetrahedrons->traversalinit();
30810  tetloop.tet = tetrahedrontraverse();
30811  edgenumber = firstindex; // in->firstnumber;
30812  while (tetloop.tet != (tetrahedron *) NULL) {
30813  // Count the number of Voronoi faces.
30814  worktet.tet = tetloop.tet;
30815  for (i = 0; i < 6; i++) {
30816  worktet.ver = edge2ver[i];
30817  ishulledge = 0;
30818  fnext(worktet, spintet);
30819  do {
30820  if (!ishulltet(spintet)) {
30821  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
30822  } else {
30823  ishulledge = 1;
30824  }
30825  fnextself(spintet);
30826  } while (spintet.tet != worktet.tet);
30827  if (spintet.tet == worktet.tet) {
30828  // Found a new edge.
30829  if (ishulledge) meshhulledges++;
30830  torg = org(worktet);
30831  tdest = dest(worktet);
30832  if (b->order == 2) { // -o2
30833  // Get the extra vertex on this edge.
30834  extralist = (point *) worktet.tet[highorderindex];
30835  pp = extralist[ver2edge[worktet.ver]];
30836  }
30837  if (out == (tetgenio *) NULL) {
30838  fprintf(outfile, "%5d %4d %4d", edgenumber,
30839  pointmark(torg) - shift, pointmark(tdest) - shift);
30840  if (b->order == 2) { // -o2
30841  fprintf(outfile, " %4d", pointmark(pp) - shift);
30842  }
30843  } else {
30844  // Output three vertices of this face;
30845  out->edgelist[index++] = pointmark(torg) - shift;
30846  out->edgelist[index++] = pointmark(tdest) - shift;
30847  if (b->order == 2) { // -o2
30848  out->o2edgelist[o2index++] = pointmark(pp) - shift;
30849  }
30850  }
30851  if (!b->nobound) {
30852  if (b->plc || b->refine) {
30853  // Check if the edge is a segment.
30854  tsspivot1(worktet, checkseg);
30855  if (checkseg.sh != NULL) {
30856  marker = shellmark(checkseg);
30857  } else {
30858  marker = 0; // It's not a segment.
30859  }
30860  } else {
30861  // Mark it if it is a hull edge.
30862  marker = ishulledge ? 1 : 0;
30863  }
30864  if (out == (tetgenio *) NULL) {
30865  fprintf(outfile, " %d", marker);
30866  } else {
30867  out->edgemarkerlist[index1++] = marker;
30868  }
30869  }
30870  if (b->neighout > 1) { // '-nn' switch.
30871  if (out == (tetgenio *) NULL) {
30872  fprintf(outfile, " %d", elemindex(tetloop.tet));
30873  } else {
30874  out->edge2tetlist[index2++] = elemindex(tetloop.tet);
30875  }
30876  // Fill the tetrahedron-to-edge map.
30877  spintet = worktet;
30878  while (1) {
30879  if (!ishulltet(spintet)) {
30880  tidx = elemindex(spintet.tet) - firstindex;
30881  tet2edgelist[tidx * 6 + ver2edge[spintet.ver]] = edgenumber;
30882  }
30883  fnextself(spintet);
30884  if (spintet.tet == worktet.tet) break;
30885  }
30886  }
30887  if (out == (tetgenio *) NULL) {
30888  fprintf(outfile, "\n");
30889  }
30890  edgenumber++;
30891  }
30892  }
30893  tetloop.tet = tetrahedrontraverse();
30894  }
30895 
30896  if (out == (tetgenio *) NULL) {
30897  fprintf(outfile, "# Generated by %s\n", b->commandline);
30898  fclose(outfile);
30899  }
30900 
30901  if (b->neighout > 1) { // -nn option
30902  long tsize = tetrahedrons->items - hullsize;
30903 
30904  if (b->facesout) { // -f option
30905  // Build the face-to-edge map (use the tet-to-edge map).
30906  long fsize = (tsize * 4l + hullsize) / 2l;
30907  int *face2edgelist = new int[fsize * 3];
30908 
30909  tetrahedrons->traversalinit();
30910  tetloop.tet = tetrahedrontraverse();
30911  int facenumber = 0; // firstindex; // in->firstnumber;
30912  while (tetloop.tet != (tetrahedron *) NULL) {
30913  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
30914  fsym(tetloop, spintet);
30915  if (ishulltet(spintet) ||
30916  (elemindex(tetloop.tet) < elemindex(spintet.tet))) {
30917  // The three edges of this face are ordered such that the
30918  // first edge is opposite to the first vertex of this face
30919  // that appears in the .face file, and so on.
30920  tidx = elemindex(tetloop.tet) - firstindex;
30921  worktet = tetloop;
30922  for (i = 0; i < 3; i++) {
30923  enextself(worktet); // The edge opposite to vertex i.
30924  int eidx = tet2edgelist[tidx * 6 + ver2edge[worktet.ver]];
30925  face2edgelist[facenumber * 3 + i] = eidx;
30926  }
30927  facenumber++;
30928  }
30929  }
30930  tetloop.tet = tetrahedrontraverse();
30931  }
30932 
30933  // Output the face-to-edge map.
30934  if (out == (tetgenio *) NULL) {
30935  strcpy(edgefilename, b->outfilename);
30936  strcat(edgefilename, ".f2e");
30937  }
30938  if (!b->quiet) {
30939  if (out == (tetgenio *) NULL) {
30940  printf("Writing %s.\n", edgefilename);
30941  } else {
30942  printf("Writing face-to-edge map.\n");
30943  }
30944  }
30945  if (out == (tetgenio *) NULL) {
30946  outfile = fopen(edgefilename, "w");
30947  for (tidx = 0; tidx < fsize; tidx++) { // Re-use `tidx'
30948  i = tidx * 3;
30949  fprintf(outfile, "%4d %d %d %d\n", tidx + in->firstnumber,
30950  face2edgelist[i], face2edgelist[i+1], face2edgelist[i+2]);
30951  }
30952  fclose(outfile);
30953  delete [] face2edgelist;
30954  } else {
30955  // Simply copy the address of the list to the output.
30956  out->face2edgelist = face2edgelist;
30957  }
30958  } // if (b->facesout)
30959 
30960  // Output the tetrahedron-to-edge map.
30961  if (out == (tetgenio *) NULL) {
30962  strcpy(edgefilename, b->outfilename);
30963  strcat(edgefilename, ".t2e");
30964  }
30965  if (!b->quiet) {
30966  if (out == (tetgenio *) NULL) {
30967  printf("Writing %s.\n", edgefilename);
30968  } else {
30969  printf("Writing tetrahedron-to-edge map.\n");
30970  }
30971  }
30972  if (out == (tetgenio *) NULL) {
30973  outfile = fopen(edgefilename, "w");
30974  for (tidx = 0; tidx < tsize; tidx++) {
30975  i = tidx * 6;
30976  fprintf(outfile, "%4d %d %d %d %d %d %d\n", tidx + in->firstnumber,
30977  tet2edgelist[i], tet2edgelist[i+1], tet2edgelist[i+2],
30978  tet2edgelist[i+3], tet2edgelist[i+4], tet2edgelist[i+5]);
30979  }
30980  fclose(outfile);
30981  delete [] tet2edgelist;
30982  } else {
30983  // Simply copy the address of the list to the output.
30984  out->tet2edgelist = tet2edgelist;
30985  }
30986  }
30987 }
30988 
30990 // //
30991 // outsubsegments() Output segments to a .edge file or a structure. //
30992 // //
30994 
30995 void tetgenmesh::outsubsegments(tetgenio* out)
30996 {
30997  FILE *outfile = NULL;
30998  char edgefilename[FILENAMESIZE];
30999  int *elist = NULL;
31000  int index, i;
31001  face edgeloop;
31002  point torg, tdest;
31003  int firstindex, shift;
31004  int marker;
31005  int edgenumber;
31006 
31007  // For -o2 option.
31008  triface workface, spintet;
31009  point *extralist, pp = NULL;
31010  int highorderindex = 11;
31011  int o2index = 0;
31012 
31013  // For -nn option.
31014  int neigh = -1;
31015  int index2 = 0;
31016 
31017  int t1ver; // used by fsymself()
31018 
31019  if (out == (tetgenio *) NULL) {
31020  strcpy(edgefilename, b->outfilename);
31021  strcat(edgefilename, ".edge");
31022  }
31023 
31024  if (!b->quiet) {
31025  if (out == (tetgenio *) NULL) {
31026  printf("Writing %s.\n", edgefilename);
31027  } else {
31028  printf("Writing edges.\n");
31029  }
31030  }
31031 
31032  if (out == (tetgenio *) NULL) {
31033  outfile = fopen(edgefilename, "w");
31034  if (outfile == (FILE *) NULL) {
31035  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
31036  terminatetetgen(this, 3);
31037  }
31038  // Number of subsegments.
31039  fprintf(outfile, "%ld 1\n", subsegs->items);
31040  } else {
31041  // Allocate memory for 'edgelist'.
31042  out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
31043  if (out->edgelist == (int *) NULL) {
31044  terminatetetgen(this, 1);
31045  }
31046  if (b->order == 2) {
31047  out->o2edgelist = new int[subsegs->items];
31048  }
31049  out->edgemarkerlist = new int[subsegs->items];
31050  if (out->edgemarkerlist == (int *) NULL) {
31051  terminatetetgen(this, 1);
31052  }
31053  if (b->neighout > 1) {
31054  out->edge2tetlist = new int[subsegs->items];
31055  }
31056  out->numberofedges = subsegs->items;
31057  elist = out->edgelist;
31058  }
31059 
31060  // Determine the first index (0 or 1).
31061  firstindex = b->zeroindex ? 0 : in->firstnumber;
31062  shift = 0; // Default no shiftment.
31063  if ((in->firstnumber == 1) && (firstindex == 0)) {
31064  shift = 1; // Shift the output indices by 1.
31065  }
31066  index = 0;
31067  i = 0;
31068 
31069  subsegs->traversalinit();
31070  edgeloop.sh = shellfacetraverse(subsegs);
31071  edgenumber = firstindex; // in->firstnumber;
31072  while (edgeloop.sh != (shellface *) NULL) {
31073  torg = sorg(edgeloop);
31074  tdest = sdest(edgeloop);
31075  if ((b->order == 2) || (b->neighout > 1)) {
31076  sstpivot1(edgeloop, workface);
31077  if (workface.tet != NULL) {
31078  // We must find a non-hull tet.
31079  if (ishulltet(workface)) {
31080  spintet = workface;
31081  while (1) {
31082  fnextself(spintet);
31083  if (!ishulltet(spintet)) break;
31084  if (spintet.tet == workface.tet) break;
31085  }
31086  workface = spintet;
31087  }
31088  }
31089  }
31090  if (b->order == 2) { // -o2
31091  // Get the extra vertex on this edge.
31092  if (workface.tet != NULL) {
31093  extralist = (point *) workface.tet[highorderindex];
31094  pp = extralist[ver2edge[workface.ver]];
31095  } else {
31096  pp = torg; // There is no extra node available.
31097  }
31098  }
31099  if (b->neighout > 1) { // -nn
31100  if (workface.tet != NULL) {
31101  neigh = elemindex(workface.tet);
31102  } else {
31103  neigh = -1;
31104  }
31105  }
31106  marker = shellmark(edgeloop);
31107  if (marker == 0) {
31108  marker = 1; // Default marker of a boundary edge is 1.
31109  }
31110  if (out == (tetgenio *) NULL) {
31111  fprintf(outfile, "%5d %4d %4d", edgenumber,
31112  pointmark(torg) - shift, pointmark(tdest) - shift);
31113  if (b->order == 2) { // -o2
31114  fprintf(outfile, " %4d", pointmark(pp) - shift);
31115  }
31116  fprintf(outfile, " %d", marker);
31117  if (b->neighout > 1) { // -nn
31118  fprintf(outfile, " %4d", neigh);
31119  }
31120  fprintf(outfile, "\n");
31121  } else {
31122  // Output three vertices of this face;
31123  elist[index++] = pointmark(torg) - shift;
31124  elist[index++] = pointmark(tdest) - shift;
31125  if (b->order == 2) { // -o2
31126  out->o2edgelist[o2index++] = pointmark(pp) - shift;
31127  }
31128  out->edgemarkerlist[i++] = marker;
31129  if (b->neighout > 1) { // -nn
31130  out->edge2tetlist[index2++] = neigh;
31131  }
31132  }
31133  edgenumber++;
31134  edgeloop.sh = shellfacetraverse(subsegs);
31135  }
31136 
31137  if (out == (tetgenio *) NULL) {
31138  fprintf(outfile, "# Generated by %s\n", b->commandline);
31139  fclose(outfile);
31140  }
31141 }
31142 
31144 // //
31145 // outneighbors() Output tet neighbors to a .neigh file or a structure. //
31146 // //
31148 
31149 void tetgenmesh::outneighbors(tetgenio* out)
31150 {
31151  FILE *outfile = NULL;
31152  char neighborfilename[FILENAMESIZE];
31153  int *nlist = NULL;
31154  int index = 0;
31155  triface tetloop, tetsym;
31156  int neighbori[4];
31157  int firstindex;
31158  int elementnumber;
31159  long ntets;
31160 
31161  if (out == (tetgenio *) NULL) {
31162  strcpy(neighborfilename, b->outfilename);
31163  strcat(neighborfilename, ".neigh");
31164  }
31165 
31166  if (!b->quiet) {
31167  if (out == (tetgenio *) NULL) {
31168  printf("Writing %s.\n", neighborfilename);
31169  } else {
31170  printf("Writing neighbors.\n");
31171  }
31172  }
31173 
31174  ntets = tetrahedrons->items - hullsize;
31175 
31176  if (out == (tetgenio *) NULL) {
31177  outfile = fopen(neighborfilename, "w");
31178  if (outfile == (FILE *) NULL) {
31179  printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
31180  terminatetetgen(this, 1);
31181  }
31182  // Number of tetrahedra, four faces per tetrahedron.
31183  fprintf(outfile, "%ld %d\n", ntets, 4);
31184  } else {
31185  // Allocate memory for 'neighborlist'.
31186  out->neighborlist = new int[ntets * 4];
31187  if (out->neighborlist == (int *) NULL) {
31188  printf("Error: Out of memory.\n");
31189  terminatetetgen(this, 1);
31190  }
31191  nlist = out->neighborlist;
31192  }
31193 
31194  // Determine the first index (0 or 1).
31195  firstindex = b->zeroindex ? 0 : in->firstnumber;
31196 
31197  tetrahedrons->traversalinit();
31198  tetloop.tet = tetrahedrontraverse();
31199  elementnumber = firstindex; // in->firstnumber;
31200  while (tetloop.tet != (tetrahedron *) NULL) {
31201  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
31202  fsym(tetloop, tetsym);
31203  if (!ishulltet(tetsym)) {
31204  neighbori[tetloop.ver] = elemindex(tetsym.tet);
31205  } else {
31206  neighbori[tetloop.ver] = -1;
31207  }
31208  }
31209  if (out == (tetgenio *) NULL) {
31210  // Tetrahedra number, neighboring tetrahedron numbers.
31211  fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
31212  neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
31213  } else {
31214  nlist[index++] = neighbori[0];
31215  nlist[index++] = neighbori[1];
31216  nlist[index++] = neighbori[2];
31217  nlist[index++] = neighbori[3];
31218  }
31219  tetloop.tet = tetrahedrontraverse();
31220  elementnumber++;
31221  }
31222 
31223  if (out == (tetgenio *) NULL) {
31224  fprintf(outfile, "# Generated by %s\n", b->commandline);
31225  fclose(outfile);
31226  }
31227 }
31228 
31230 // //
31231 // outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
31232 // and .v.cell. //
31233 // //
31234 // The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
31235 // The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
31236 // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
31237 // unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
31238 // A Voronoi face is the convex hull of all Voronoi vertices around a common //
31239 // Delaunay edge. It is a closed polygon for any internal Delaunay edge. At a//
31240 // ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
31241 // onoi vertices around a common Delaunay vertex. It is a polytope for any //
31242 // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
31243 // vertex belonging to the convex hull. //
31244 // //
31245 // NOTE: This routine is only used when the input is only a set of point. //
31246 // Comment: Special thanks to Victor Liu for finding and fixing few bugs. //
31247 // //
31249 
31250 void tetgenmesh::outvoronoi(tetgenio* out)
31251 {
31252  FILE *outfile = NULL;
31253  char outfilename[FILENAMESIZE];
31254  tetgenio::voroedge *vedge = NULL;
31255  tetgenio::vorofacet *vfacet = NULL;
31256  arraypool *tetlist, *ptlist;
31257  triface tetloop, worktet, spintet, firsttet;
31258  point pt[4], ploop, neipt;
31259  REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
31260  long ntets, faces, edges;
31261  int *indexarray, *fidxs, *eidxs;
31262  int arraysize, *vertarray = NULL;
31263  int vpointcount, vedgecount, vfacecount, tcount;
31264  int ishullvert, ishullface;
31265  int index, shift, end1, end2;
31266  int i, j;
31267 
31268  int t1ver; // used by fsymself()
31269 
31270  // Output Voronoi vertices to .v.node file.
31271  if (out == (tetgenio *) NULL) {
31272  strcpy(outfilename, b->outfilename);
31273  strcat(outfilename, ".v.node");
31274  }
31275 
31276  if (!b->quiet) {
31277  if (out == (tetgenio *) NULL) {
31278  printf("Writing %s.\n", outfilename);
31279  } else {
31280  printf("Writing Voronoi vertices.\n");
31281  }
31282  }
31283 
31284  // Determine the first index (0 or 1).
31285  shift = (b->zeroindex ? 0 : in->firstnumber);
31286 
31287  // Each face and edge of the tetrahedral mesh will be indexed for indexing
31288  // the Voronoi edges and facets. Indices of faces and edges are saved in
31289  // each tetrahedron (including hull tets).
31290 
31291  // Allocate the total space once.
31292  indexarray = new int[tetrahedrons->items * 10];
31293 
31294  // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
31295  // for element markers, flags.
31296  i = 0;
31297  tetrahedrons->traversalinit();
31298  tetloop.tet = alltetrahedrontraverse();
31299  while (tetloop.tet != NULL) {
31300  tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
31301  i++;
31302  tetloop.tet = alltetrahedrontraverse();
31303  }
31304 
31305  // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
31306  ntets = tetrahedrons->items - hullsize;
31307  // The number of Delaunay faces (Voronoi edges).
31308  faces = (4l * ntets + hullsize) / 2l;
31309  // The number of Delaunay edges (Voronoi faces).
31310  long vsize = points->items - dupverts - unuverts;
31311  if (b->weighted) vsize -= nonregularcount;
31312  if (!nonconvex) {
31313  edges = vsize + faces - ntets - 1;
31314  } else {
31315  if (meshedges == 0l) {
31316  numberedges(); // Count edges.
31317  }
31318  edges = meshedges;
31319  }
31320 
31321  if (out == (tetgenio *) NULL) {
31322  outfile = fopen(outfilename, "w");
31323  if (outfile == (FILE *) NULL) {
31324  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31325  terminatetetgen(this, 3);
31326  }
31327  // Number of voronoi points, 3 dim, no attributes, no marker.
31328  fprintf(outfile, "%ld 3 0 0\n", ntets);
31329  } else {
31330  // Allocate space for 'vpointlist'.
31331  out->numberofvpoints = (int) ntets;
31332  out->vpointlist = new REAL[out->numberofvpoints * 3];
31333  if (out->vpointlist == (REAL *) NULL) {
31334  terminatetetgen(this, 1);
31335  }
31336  }
31337 
31338  // Output Voronoi vertices (the circumcenters of tetrahedra).
31339  tetrahedrons->traversalinit();
31340  tetloop.tet = tetrahedrontraverse();
31341  vpointcount = 0; // The (internal) v-index always starts from 0.
31342  index = 0;
31343  while (tetloop.tet != (tetrahedron *) NULL) {
31344  for (i = 0; i < 4; i++) {
31345  pt[i] = (point) tetloop.tet[4 + i];
31346  setpoint2tet(pt[i], encode(tetloop));
31347  }
31348  if (b->weighted) {
31349  orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3],
31350  pt[3][3], ccent, NULL);
31351  } else {
31352  circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
31353  }
31354  if (out == (tetgenio *) NULL) {
31355  fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
31356  ccent[0], ccent[1], ccent[2]);
31357  } else {
31358  out->vpointlist[index++] = ccent[0];
31359  out->vpointlist[index++] = ccent[1];
31360  out->vpointlist[index++] = ccent[2];
31361  }
31362  setelemindex(tetloop.tet, vpointcount);
31363  vpointcount++;
31364  tetloop.tet = tetrahedrontraverse();
31365  }
31366 
31367  if (out == (tetgenio *) NULL) {
31368  fprintf(outfile, "# Generated by %s\n", b->commandline);
31369  fclose(outfile);
31370  }
31371 
31372  // Output Voronoi edges to .v.edge file.
31373  if (out == (tetgenio *) NULL) {
31374  strcpy(outfilename, b->outfilename);
31375  strcat(outfilename, ".v.edge");
31376  }
31377 
31378  if (!b->quiet) {
31379  if (out == (tetgenio *) NULL) {
31380  printf("Writing %s.\n", outfilename);
31381  } else {
31382  printf("Writing Voronoi edges.\n");
31383  }
31384  }
31385 
31386  if (out == (tetgenio *) NULL) {
31387  outfile = fopen(outfilename, "w");
31388  if (outfile == (FILE *) NULL) {
31389  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31390  terminatetetgen(this, 3);
31391  }
31392  // Number of Voronoi edges, no marker.
31393  fprintf(outfile, "%ld 0\n", faces);
31394  } else {
31395  // Allocate space for 'vpointlist'.
31396  out->numberofvedges = (int) faces;
31397  out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
31398  }
31399 
31400  // Output the Voronoi edges.
31401  tetrahedrons->traversalinit();
31402  tetloop.tet = tetrahedrontraverse();
31403  vedgecount = 0; // D-Face (V-edge) index (from zero).
31404  index = 0; // The Delaunay-face index.
31405  while (tetloop.tet != (tetrahedron *) NULL) {
31406  // Count the number of Voronoi edges. Look at the four faces of each
31407  // tetrahedron. Count the face if the tetrahedron's index is
31408  // smaller than its neighbor's or the neighbor is outside.
31409  end1 = elemindex(tetloop.tet);
31410  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
31411  fsym(tetloop, worktet);
31412  if (ishulltet(worktet) ||
31413  (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
31414  // Found a Voronoi edge. Operate on it.
31415  if (out == (tetgenio *) NULL) {
31416  fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
31417  } else {
31418  vedge = &(out->vedgelist[index++]);
31419  vedge->v1 = end1 + shift;
31420  }
31421  if (!ishulltet(worktet)) {
31422  end2 = elemindex(worktet.tet);
31423  } else {
31424  end2 = -1;
31425  }
31426  // Note that end2 may be -1 (worktet.tet is outside).
31427  if (end2 == -1) {
31428  // Calculate the out normal of this hull face.
31429  pt[0] = dest(worktet);
31430  pt[1] = org(worktet);
31431  pt[2] = apex(worktet);
31432  for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
31433  for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
31434  cross(vec1, vec2, infvec);
31435  // Normalize it.
31436  L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
31437  + infvec[2] * infvec[2]);
31438  if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
31439  if (out == (tetgenio *) NULL) {
31440  fprintf(outfile, " -1");
31441  fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
31442  } else {
31443  vedge->v2 = -1;
31444  vedge->vnormal[0] = infvec[0];
31445  vedge->vnormal[1] = infvec[1];
31446  vedge->vnormal[2] = infvec[2];
31447  }
31448  } else {
31449  if (out == (tetgenio *) NULL) {
31450  fprintf(outfile, " %4d\n", end2 + shift);
31451  } else {
31452  vedge->v2 = end2 + shift;
31453  vedge->vnormal[0] = 0.0;
31454  vedge->vnormal[1] = 0.0;
31455  vedge->vnormal[2] = 0.0;
31456  }
31457  }
31458  // Save the V-edge index in this tet and its neighbor.
31459  fidxs = (int *) (tetloop.tet[11]);
31460  fidxs[tetloop.ver] = vedgecount;
31461  fidxs = (int *) (worktet.tet[11]);
31462  fidxs[worktet.ver & 3] = vedgecount;
31463  vedgecount++;
31464  }
31465  } // tetloop.ver
31466  tetloop.tet = tetrahedrontraverse();
31467  }
31468 
31469  if (out == (tetgenio *) NULL) {
31470  fprintf(outfile, "# Generated by %s\n", b->commandline);
31471  fclose(outfile);
31472  }
31473 
31474  // Output Voronoi faces to .v.face file.
31475  if (out == (tetgenio *) NULL) {
31476  strcpy(outfilename, b->outfilename);
31477  strcat(outfilename, ".v.face");
31478  }
31479 
31480  if (!b->quiet) {
31481  if (out == (tetgenio *) NULL) {
31482  printf("Writing %s.\n", outfilename);
31483  } else {
31484  printf("Writing Voronoi faces.\n");
31485  }
31486  }
31487 
31488  if (out == (tetgenio *) NULL) {
31489  outfile = fopen(outfilename, "w");
31490  if (outfile == (FILE *) NULL) {
31491  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31492  terminatetetgen(this, 3);
31493  }
31494  // Number of Voronoi faces.
31495  fprintf(outfile, "%ld 0\n", edges);
31496  } else {
31497  out->numberofvfacets = edges;
31498  out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
31499  if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
31500  terminatetetgen(this, 1);
31501  }
31502  }
31503 
31504  // Output the Voronoi facets.
31505  tetrahedrons->traversalinit();
31506  tetloop.tet = tetrahedrontraverse();
31507  vfacecount = 0; // D-edge (V-facet) index (from zero).
31508  while (tetloop.tet != (tetrahedron *) NULL) {
31509  // Count the number of Voronoi faces. Look at the six edges of each
31510  // tetrahedron. Count the edge only if the tetrahedron's index is
31511  // smaller than those of all other tetrahedra that share the edge.
31512  worktet.tet = tetloop.tet;
31513  for (i = 0; i < 6; i++) {
31514  worktet.ver = edge2ver[i];
31515  // Count the number of faces at this edge. If the edge is a hull edge,
31516  // the face containing dummypoint is also counted.
31517  //ishulledge = 0; // Is it a hull edge.
31518  tcount = 0;
31519  firsttet = worktet;
31520  spintet = worktet;
31521  while (1) {
31522  tcount++;
31523  fnextself(spintet);
31524  if (spintet.tet == worktet.tet) break;
31525  if (!ishulltet(spintet)) {
31526  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
31527  } else {
31528  //ishulledge = 1;
31529  if (apex(spintet) == dummypoint) {
31530  // We make this V-edge appear in the end of the edge list.
31531  fnext(spintet, firsttet);
31532  }
31533  }
31534  } // while (1)
31535  if (spintet.tet == worktet.tet) {
31536  // Found a Voronoi facet. Operate on it.
31537  pt[0] = org(worktet);
31538  pt[1] = dest(worktet);
31539  end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
31540  end2 = pointmark(pt[1]) - in->firstnumber;
31541  if (out == (tetgenio *) NULL) {
31542  fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
31543  end1 + shift, end2 + shift, tcount);
31544  } else {
31545  vfacet = &(out->vfacetlist[vfacecount]);
31546  vfacet->c1 = end1 + shift;
31547  vfacet->c2 = end2 + shift;
31548  vfacet->elist = new int[tcount + 1];
31549  vfacet->elist[0] = tcount;
31550  index = 1;
31551  }
31552  // Output V-edges of this V-facet.
31553  spintet = firsttet; //worktet;
31554  while (1) {
31555  fidxs = (int *) (spintet.tet[11]);
31556  if (apex(spintet) != dummypoint) {
31557  vedgecount = fidxs[spintet.ver & 3];
31558  ishullface = 0;
31559  } else {
31560  ishullface = 1; // It's not a real face.
31561  }
31562  if (out == (tetgenio *) NULL) {
31563  fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1);
31564  } else {
31565  vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
31566  }
31567  // Save the V-facet index in this tet at this edge.
31568  eidxs = &(fidxs[4]);
31569  eidxs[ver2edge[spintet.ver]] = vfacecount;
31570  // Go to the next face.
31571  fnextself(spintet);
31572  if (spintet.tet == firsttet.tet) break;
31573  } // while (1)
31574  if (out == (tetgenio *) NULL) {
31575  fprintf(outfile, "\n");
31576  }
31577  vfacecount++;
31578  } // if (spintet.tet == worktet.tet)
31579  } // if (i = 0; i < 6; i++)
31580  tetloop.tet = tetrahedrontraverse();
31581  }
31582 
31583  if (out == (tetgenio *) NULL) {
31584  fprintf(outfile, "# Generated by %s\n", b->commandline);
31585  fclose(outfile);
31586  }
31587 
31588  // Output Voronoi cells to .v.cell file.
31589  if (out == (tetgenio *) NULL) {
31590  strcpy(outfilename, b->outfilename);
31591  strcat(outfilename, ".v.cell");
31592  }
31593 
31594  if (!b->quiet) {
31595  if (out == (tetgenio *) NULL) {
31596  printf("Writing %s.\n", outfilename);
31597  } else {
31598  printf("Writing Voronoi cells.\n");
31599  }
31600  }
31601 
31602  if (out == (tetgenio *) NULL) {
31603  outfile = fopen(outfilename, "w");
31604  if (outfile == (FILE *) NULL) {
31605  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31606  terminatetetgen(this, 3);
31607  }
31608  // Number of Voronoi cells.
31609  fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
31610  } else {
31611  out->numberofvcells = points->items - unuverts - dupverts;
31612  out->vcelllist = new int*[out->numberofvcells];
31613  if (out->vcelllist == (int **) NULL) {
31614  terminatetetgen(this, 1);
31615  }
31616  }
31617 
31618  // Output Voronoi cells.
31619  tetlist = cavetetlist;
31620  ptlist = cavetetvertlist;
31621  points->traversalinit();
31622  ploop = pointtraverse();
31623  vpointcount = 0;
31624  while (ploop != (point) NULL) {
31625  if ((pointtype(ploop) != UNUSEDVERTEX) &&
31626  (pointtype(ploop) != DUPLICATEDVERTEX) &&
31627  (pointtype(ploop) != NREGULARVERTEX)) {
31628  getvertexstar(1, ploop, tetlist, ptlist, NULL);
31629  // Mark all vertices. Check if it is a hull vertex.
31630  ishullvert = 0;
31631  for (i = 0; i < ptlist->objects; i++) {
31632  neipt = * (point *) fastlookup(ptlist, i);
31633  if (neipt != dummypoint) {
31634  pinfect(neipt);
31635  } else {
31636  ishullvert = 1;
31637  }
31638  }
31639  tcount = (int) ptlist->objects;
31640  if (out == (tetgenio *) NULL) {
31641  fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
31642  } else {
31643  arraysize = tcount;
31644  vertarray = new int[arraysize + 1];
31645  out->vcelllist[vpointcount] = vertarray;
31646  vertarray[0] = tcount;
31647  index = 1;
31648  }
31649  // List Voronoi facets bounding this cell.
31650  for (i = 0; i < tetlist->objects; i++) {
31651  worktet = * (triface *) fastlookup(tetlist, i);
31652  // Let 'worktet' be [a,b,c,d] where d = ploop.
31653  for (j = 0; j < 3; j++) {
31654  neipt = org(worktet); // neipt is a, or b, or c
31655  // Skip the dummypoint.
31656  if (neipt != dummypoint) {
31657  if (pinfected(neipt)) {
31658  // It's not processed yet.
31659  puninfect(neipt);
31660  // Go to the DT edge [a,d], or [b,d], or [c,d].
31661  esym(worktet, spintet);
31662  enextself(spintet);
31663  // Get the V-face dual to this edge.
31664  eidxs = (int *) spintet.tet[11];
31665  vfacecount = eidxs[4 + ver2edge[spintet.ver]];
31666  if (out == (tetgenio *) NULL) {
31667  fprintf(outfile, " %d", vfacecount + shift);
31668  } else {
31669  vertarray[index++] = vfacecount + shift;
31670  }
31671  }
31672  }
31673  enextself(worktet);
31674  } // j
31675  } // i
31676  if (ishullvert) {
31677  // Add a hull facet (-1) to the facet list.
31678  if (out == (tetgenio *) NULL) {
31679  fprintf(outfile, " -1");
31680  } else {
31681  vertarray[index++] = -1;
31682  }
31683  }
31684  if (out == (tetgenio *) NULL) {
31685  fprintf(outfile, "\n");
31686  }
31687  tetlist->restart();
31688  ptlist->restart();
31689  vpointcount++;
31690  }
31691  ploop = pointtraverse();
31692  }
31693 
31694  // Delete the space for face/edge indices.
31695  delete [] indexarray;
31696 
31697  if (out == (tetgenio *) NULL) {
31698  fprintf(outfile, "# Generated by %s\n", b->commandline);
31699  fclose(outfile);
31700  }
31701 }
31702 
31704 // //
31705 // outsmesh() Write surface mesh to a .smesh file, which can be read and //
31706 // tetrahedralized by TetGen. //
31707 // //
31708 // You can specify a filename (without suffix) in 'smfilename'. If you don't //
31709 // supply a filename (let smfilename be NULL), the default name stored in //
31710 // 'tetgenbehavior' will be used. //
31711 // //
31713 
31714 void tetgenmesh::outsmesh(char* smfilename)
31715 {
31716  FILE *outfile;
31717  char nodfilename[FILENAMESIZE];
31718  char smefilename[FILENAMESIZE];
31719  face faceloop;
31720  point p1, p2, p3;
31721  int firstindex, shift;
31722  int bmark;
31723  int marker;
31724  int i;
31725 
31726  if (smfilename != (char *) NULL && smfilename[0] != '\0') {
31727  strcpy(smefilename, smfilename);
31728  } else if (b->outfilename[0] != '\0') {
31729  strcpy(smefilename, b->outfilename);
31730  } else {
31731  strcpy(smefilename, "unnamed");
31732  }
31733  strcpy(nodfilename, smefilename);
31734  strcat(smefilename, ".smesh");
31735  strcat(nodfilename, ".node");
31736 
31737  if (!b->quiet) {
31738  printf("Writing %s.\n", smefilename);
31739  }
31740  outfile = fopen(smefilename, "w");
31741  if (outfile == (FILE *) NULL) {
31742  printf("File I/O Error: Cannot create file %s.\n", smefilename);
31743  return;
31744  }
31745 
31746  // Determine the first index (0 or 1).
31747  firstindex = b->zeroindex ? 0 : in->firstnumber;
31748  shift = 0; // Default no shiftment.
31749  if ((in->firstnumber == 1) && (firstindex == 0)) {
31750  shift = 1; // Shift the output indices by 1.
31751  }
31752 
31753  fprintf(outfile, "# %s. TetGen's input file.\n", smefilename);
31754  fprintf(outfile, "\n# part 1: node list.\n");
31755  fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename);
31756 
31757  marker = 0; // avoid compile warning.
31758  bmark = !b->nobound && (in->facetmarkerlist || in->trifacemarkerlist);
31759 
31760  fprintf(outfile, "\n# part 2: facet list.\n");
31761  // Number of facets, boundary marker.
31762  fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
31763 
31764  subfaces->traversalinit();
31765  faceloop.sh = shellfacetraverse(subfaces);
31766  while (faceloop.sh != (shellface *) NULL) {
31767  p1 = sorg(faceloop);
31768  p2 = sdest(faceloop);
31769  p3 = sapex(faceloop);
31770  if (bmark) {
31771  marker = shellmark(faceloop);
31772  }
31773  fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift,
31774  pointmark(p2) - shift, pointmark(p3) - shift);
31775  if (bmark) {
31776  fprintf(outfile, " %d", marker);
31777  }
31778  fprintf(outfile, "\n");
31779  faceloop.sh = shellfacetraverse(subfaces);
31780  }
31781 
31782  // Copy input holelist.
31783  fprintf(outfile, "\n# part 3: hole list.\n");
31784  fprintf(outfile, "%d\n", in->numberofholes);
31785  for (i = 0; i < in->numberofholes; i++) {
31786  fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber,
31787  in->holelist[i * 3], in->holelist[i * 3 + 1],
31788  in->holelist[i * 3 + 2]);
31789  }
31790 
31791  // Copy input regionlist.
31792  fprintf(outfile, "\n# part 4: region list.\n");
31793  fprintf(outfile, "%d\n", in->numberofregions);
31794  for (i = 0; i < in->numberofregions; i++) {
31795  fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber,
31796  in->regionlist[i * 5], in->regionlist[i * 5 + 1],
31797  in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
31798  in->regionlist[i * 5 + 4]);
31799  }
31800 
31801  fprintf(outfile, "# Generated by %s\n", b->commandline);
31802  fclose(outfile);
31803 }
31804 
31806 // //
31807 // outmesh2medit() Write mesh to a .mesh file, which can be read and //
31808 // rendered by Medit (a free mesh viewer from INRIA). //
31809 // //
31810 // You can specify a filename (without suffix) in 'mfilename'. If you don't //
31811 // supply a filename (let mfilename be NULL), the default name stored in //
31812 // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
31813 // //
31815 
31816 void tetgenmesh::outmesh2medit(char* mfilename)
31817 {
31818  FILE *outfile;
31819  char mefilename[FILENAMESIZE];
31820  tetrahedron* tetptr;
31821  triface tface, tsymface;
31822  face segloop, checkmark;
31823  point ptloop, p1, p2, p3, p4;
31824  long ntets, faces;
31825  int pointnumber;
31826  int marker;
31827  int i;
31828 
31829  if (mfilename != (char *) NULL && mfilename[0] != '\0') {
31830  strcpy(mefilename, mfilename);
31831  } else if (b->outfilename[0] != '\0') {
31832  strcpy(mefilename, b->outfilename);
31833  } else {
31834  strcpy(mefilename, "unnamed");
31835  }
31836  strcat(mefilename, ".mesh");
31837 
31838  if (!b->quiet) {
31839  printf("Writing %s.\n", mefilename);
31840  }
31841  outfile = fopen(mefilename, "w");
31842  if (outfile == (FILE *) NULL) {
31843  printf("File I/O Error: Cannot create file %s.\n", mefilename);
31844  return;
31845  }
31846 
31847  fprintf(outfile, "MeshVersionFormatted 1\n");
31848  fprintf(outfile, "\n");
31849  fprintf(outfile, "Dimension\n");
31850  fprintf(outfile, "3\n");
31851  fprintf(outfile, "\n");
31852 
31853  fprintf(outfile, "\n# Set of mesh vertices\n");
31854  fprintf(outfile, "Vertices\n");
31855  fprintf(outfile, "%ld\n", points->items);
31856 
31857  points->traversalinit();
31858  ptloop = pointtraverse();
31859  pointnumber = 1; // Medit need start number form 1.
31860  while (ptloop != (point) NULL) {
31861  // Point coordinates.
31862  fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
31863  if (in->numberofpointattributes > 0) {
31864  // Write an attribute, ignore others if more than one.
31865  fprintf(outfile, " %.17g\n", ptloop[3]);
31866  } else {
31867  fprintf(outfile, " 0\n");
31868  }
31869  setpointmark(ptloop, pointnumber);
31870  ptloop = pointtraverse();
31871  pointnumber++;
31872  }
31873 
31874  // Compute the number of faces.
31875  ntets = tetrahedrons->items - hullsize;
31876  faces = (ntets * 4l + hullsize) / 2l;
31877 
31878  fprintf(outfile, "\n# Set of Triangles\n");
31879  fprintf(outfile, "Triangles\n");
31880  fprintf(outfile, "%ld\n", faces);
31881 
31882  tetrahedrons->traversalinit();
31883  tface.tet = tetrahedrontraverse();
31884  while (tface.tet != (tetrahedron *) NULL) {
31885  for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
31886  fsym(tface, tsymface);
31887  if (ishulltet(tsymface) ||
31888  (elemindex(tface.tet) < elemindex(tsymface.tet))) {
31889  p1 = org (tface);
31890  p2 = dest(tface);
31891  p3 = apex(tface);
31892  fprintf(outfile, "%5d %5d %5d",
31893  pointmark(p1), pointmark(p2), pointmark(p3));
31894  // Check if it is a subface.
31895  tspivot(tface, checkmark);
31896  if (checkmark.sh == NULL) {
31897  marker = 0; // It is an inner face. It's marker is 0.
31898  } else {
31899  marker = shellmark(checkmark);
31900  }
31901  fprintf(outfile, " %d\n", marker);
31902  }
31903  }
31904  tface.tet = tetrahedrontraverse();
31905  }
31906 
31907  fprintf(outfile, "\n# Set of Tetrahedra\n");
31908  fprintf(outfile, "Tetrahedra\n");
31909  fprintf(outfile, "%ld\n", ntets);
31910 
31911  tetrahedrons->traversalinit();
31912  tetptr = tetrahedrontraverse();
31913  while (tetptr != (tetrahedron *) NULL) {
31914  if (!b->reversetetori) {
31915  p1 = (point) tetptr[4];
31916  p2 = (point) tetptr[5];
31917  } else {
31918  p1 = (point) tetptr[5];
31919  p2 = (point) tetptr[4];
31920  }
31921  p3 = (point) tetptr[6];
31922  p4 = (point) tetptr[7];
31923  fprintf(outfile, "%5d %5d %5d %5d",
31924  pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
31925  if (numelemattrib > 0) {
31926  fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
31927  } else {
31928  fprintf(outfile, " 0");
31929  }
31930  fprintf(outfile, "\n");
31931  tetptr = tetrahedrontraverse();
31932  }
31933 
31934  fprintf(outfile, "\nCorners\n");
31935  fprintf(outfile, "%d\n", in->numberofpoints);
31936 
31937  for (i = 0; i < in->numberofpoints; i++) {
31938  fprintf(outfile, "%4d\n", i + 1);
31939  }
31940 
31941  if (b->plc || b->refine) {
31942  fprintf(outfile, "\nEdges\n");
31943  fprintf(outfile, "%ld\n", subsegs->items);
31944 
31945  subsegs->traversalinit();
31946  segloop.sh = shellfacetraverse(subsegs);
31947  while (segloop.sh != (shellface *) NULL) {
31948  p1 = sorg(segloop);
31949  p2 = sdest(segloop);
31950  fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2));
31951  marker = shellmark(segloop);
31952  fprintf(outfile, " %d\n", marker);
31953  segloop.sh = shellfacetraverse(subsegs);
31954  }
31955  }
31956 
31957  fprintf(outfile, "\nEnd\n");
31958  fclose(outfile);
31959 }
31960 
31961 
31962 
31963 
31964 
31966 // //
31967 // outmesh2vtk() Save mesh to file in VTK Legacy format. //
31968 // //
31969 // This function was contributed by Bryn Llyod from ETH, 2007. //
31970 // //
31972 
31973 void tetgenmesh::outmesh2vtk(char* ofilename)
31974 {
31975  FILE *outfile;
31976  char vtkfilename[FILENAMESIZE];
31977  point pointloop, p1, p2, p3, p4;
31978  tetrahedron* tptr;
31979  double x, y, z;
31980  int n1, n2, n3, n4;
31981  int nnodes = 4;
31982  int celltype = 10;
31983 
31984  if (b->order == 2) {
31985  printf(" Write VTK not implemented for order 2 elements \n");
31986  return;
31987  }
31988 
31989  int NEL = tetrahedrons->items - hullsize;
31990  int NN = points->items;
31991 
31992  if (ofilename != (char *) NULL && ofilename[0] != '\0') {
31993  strcpy(vtkfilename, ofilename);
31994  } else if (b->outfilename[0] != '\0') {
31995  strcpy(vtkfilename, b->outfilename);
31996  } else {
31997  strcpy(vtkfilename, "unnamed");
31998  }
31999  strcat(vtkfilename, ".vtk");
32000 
32001  if (!b->quiet) {
32002  printf("Writing %s.\n", vtkfilename);
32003  }
32004  outfile = fopen(vtkfilename, "w");
32005  if (outfile == (FILE *) NULL) {
32006  printf("File I/O Error: Cannot create file %s.\n", vtkfilename);
32007  return;
32008  }
32009 
32010  //always write big endian
32011  //bool ImALittleEndian = !testIsBigEndian();
32012 
32013  fprintf(outfile, "# vtk DataFile Version 2.0\n");
32014  fprintf(outfile, "Unstructured Grid\n");
32015  fprintf(outfile, "ASCII\n"); // BINARY
32016  fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
32017  fprintf(outfile, "POINTS %d double\n", NN);
32018 
32019  points->traversalinit();
32020  pointloop = pointtraverse();
32021  for(int id=0; id<NN && pointloop != (point) NULL; id++){
32022  x = pointloop[0];
32023  y = pointloop[1];
32024  z = pointloop[2];
32025  fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
32026  pointloop = pointtraverse();
32027  }
32028  fprintf(outfile, "\n");
32029 
32030  fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
32031  //NEL rows, each has 1 type id + 4 node id's
32032 
32033  tetrahedrons->traversalinit();
32034  tptr = tetrahedrontraverse();
32035  //elementnumber = firstindex; // in->firstnumber;
32036  while (tptr != (tetrahedron *) NULL) {
32037  if (!b->reversetetori) {
32038  p1 = (point) tptr[4];
32039  p2 = (point) tptr[5];
32040  } else {
32041  p1 = (point) tptr[5];
32042  p2 = (point) tptr[4];
32043  }
32044  p3 = (point) tptr[6];
32045  p4 = (point) tptr[7];
32046  n1 = pointmark(p1) - in->firstnumber;
32047  n2 = pointmark(p2) - in->firstnumber;
32048  n3 = pointmark(p3) - in->firstnumber;
32049  n4 = pointmark(p4) - in->firstnumber;
32050  fprintf(outfile, "%d %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
32051  tptr = tetrahedrontraverse();
32052  }
32053  fprintf(outfile, "\n");
32054 
32055  fprintf(outfile, "CELL_TYPES %d\n", NEL);
32056  for(int tid=0; tid<NEL; tid++){
32057  fprintf(outfile, "%d\n", celltype);
32058  }
32059  fprintf(outfile, "\n");
32060 
32061  if (numelemattrib > 0) {
32062  // Output tetrahedra region attributes.
32063  fprintf(outfile, "CELL_DATA %d\n", NEL);
32064  fprintf(outfile, "SCALARS cell_scalars int 1\n");
32065  fprintf(outfile, "LOOKUP_TABLE default\n");
32066  tetrahedrons->traversalinit();
32067  tptr = tetrahedrontraverse();
32068  while (tptr != (tetrahedron *) NULL) {
32069  fprintf(outfile, "%d\n", (int) elemattribute(tptr, numelemattrib - 1));
32070  tptr = tetrahedrontraverse();
32071  }
32072  fprintf(outfile, "\n");
32073  }
32074 
32075  fclose(outfile);
32076 }
32077 
32081 
32085 
32087 // //
32088 // tetrahedralize() The interface for users using TetGen library to //
32089 // generate tetrahedral meshes with all features. //
32090 // //
32091 // The sequence is roughly as follows. Many of these steps can be skipped, //
32092 // depending on the command line switches. //
32093 // //
32094 // - Initialize constants and parse the command line. //
32095 // - Read the vertices from a file and either //
32096 // - tetrahedralize them (no -r), or //
32097 // - read an old mesh from files and reconstruct it (-r). //
32098 // - Insert the boundary segments and facets (-p or -Y). //
32099 // - Read the holes (-p), regional attributes (-pA), and regional volume //
32100 // constraints (-pa). Carve the holes and concavities, and spread the //
32101 // regional attributes and volume constraints. //
32102 // - Enforce the constraints on minimum quality bound (-q) and maximum //
32103 // volume (-a), and a mesh size function (-m). //
32104 // - Optimize the mesh wrt. specified quality measures (-O and -o). //
32105 // - Write the output files and print the statistics. //
32106 // - Check the consistency of the mesh (-C). //
32107 // //
32109 
32110 void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
32111  tetgenio *addin, tetgenio *bgmin)
32112 {
32113  tetgenmesh m;
32114  clock_t tv[12], ts[5]; // Timing informations (defined in time.h)
32115  REAL cps = (REAL) CLOCKS_PER_SEC;
32116 
32117  tv[0] = clock();
32118 
32119  m.b = b;
32120  m.in = in;
32121  m.addin = addin;
32122 
32123  if (b->metric && bgmin && (bgmin->numberofpoints > 0)) {
32124  m.bgm = new tetgenmesh(); // Create an empty background mesh.
32125  m.bgm->b = b;
32126  m.bgm->in = bgmin;
32127  }
32128 
32129  m.initializepools();
32130  m.transfernodes();
32131 
32132  exactinit(b->verbose, b->noexact, b->nostaticfilter,
32133  m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
32134 
32135  tv[1] = clock();
32136 
32137  if (b->refine) { // -r
32138  m.reconstructmesh();
32139  } else { // -p
32140  m.incrementaldelaunay(ts[0]);
32141  }
32142 
32143  tv[2] = clock();
32144 
32145  if (!b->quiet) {
32146  if (b->refine) {
32147  printf("Mesh reconstruction seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
32148  } else {
32149  printf("Delaunay seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
32150  if (b->verbose) {
32151  printf(" Point sorting seconds: %g\n", ((REAL)(ts[0]-tv[1])) / cps);
32152 
32153  }
32154  }
32155  }
32156 
32157  if (b->plc && !b->refine) { // -p
32158  m.meshsurface();
32159 
32160  ts[0] = clock();
32161 
32162  if (!b->quiet) {
32163  printf("Surface mesh seconds: %g\n", ((REAL)(ts[0]-tv[2])) / cps);
32164  }
32165 
32166  if (b->diagnose) { // -d
32167  m.detectinterfaces();
32168 
32169  ts[1] = clock();
32170 
32171  if (!b->quiet) {
32172  printf("Self-intersection seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
32173  }
32174 
32175  // Only output when self-intersecting faces exist.
32176  if (m.subfaces->items > 0l) {
32177  m.outnodes(out);
32178  m.outsubfaces(out);
32179  }
32180 
32181  return;
32182  }
32183  }
32184 
32185 
32186  tv[3] = clock();
32187 
32188  if ((b->metric) && (m.bgm != NULL)) { // -m
32189  m.bgm->initializepools();
32190  m.bgm->transfernodes();
32191  m.bgm->reconstructmesh();
32192 
32193  ts[0] = clock();
32194 
32195  if (!b->quiet) {
32196  printf("Background mesh reconstruct seconds: %g\n",
32197  ((REAL)(ts[0] - tv[3])) / cps);
32198  }
32199 
32200  if (b->metric) { // -m
32201  m.interpolatemeshsize();
32202 
32203  ts[1] = clock();
32204 
32205  if (!b->quiet) {
32206  printf("Size interpolating seconds: %g\n",((REAL)(ts[1]-ts[0])) / cps);
32207  }
32208  }
32209  }
32210 
32211  tv[4] = clock();
32212 
32213  if (b->plc && !b->refine) { // -p
32214  if (b->nobisect) { // -Y
32215  m.recoverboundary(ts[0]);
32216  } else {
32217  m.constraineddelaunay(ts[0]);
32218  }
32219 
32220  ts[1] = clock();
32221 
32222  if (!b->quiet) {
32223  if (b->nobisect) {
32224  printf("Boundary recovery ");
32225  } else {
32226  printf("Constrained Delaunay ");
32227  }
32228  printf("seconds: %g\n", ((REAL)(ts[1] - tv[4])) / cps);
32229  if (b->verbose) {
32230  printf(" Segment recovery seconds: %g\n",((REAL)(ts[0]-tv[4]))/ cps);
32231  printf(" Facet recovery seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
32232  }
32233  }
32234 
32235  m.carveholes();
32236 
32237  ts[2] = clock();
32238 
32239  if (!b->quiet) {
32240  printf("Exterior tets removal seconds: %g\n",((REAL)(ts[2]-ts[1]))/cps);
32241  }
32242 
32243  if (b->nobisect) { // -Y
32244  if (m.subvertstack->objects > 0l) {
32245  m.suppresssteinerpoints();
32246 
32247  ts[3] = clock();
32248 
32249  if (!b->quiet) {
32250  printf("Steiner suppression seconds: %g\n",
32251  ((REAL)(ts[3]-ts[2]))/cps);
32252  }
32253  }
32254  }
32255  }
32256 
32257  tv[5] = clock();
32258 
32259  if (b->coarsen) { // -R
32260  m.meshcoarsening();
32261  }
32262 
32263  tv[6] = clock();
32264 
32265  if (!b->quiet) {
32266  if (b->coarsen) {
32267  printf("Mesh coarsening seconds: %g\n", ((REAL)(tv[6] - tv[5])) / cps);
32268  }
32269  }
32270 
32271  if ((b->plc && b->nobisect) || b->coarsen) {
32272  m.recoverdelaunay();
32273  }
32274 
32275  tv[7] = clock();
32276 
32277  if (!b->quiet) {
32278  if ((b->plc && b->nobisect) || b->coarsen) {
32279  printf("Delaunay recovery seconds: %g\n", ((REAL)(tv[7] - tv[6]))/cps);
32280  }
32281  }
32282 
32283  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
32284  if ((addin != NULL) && (addin->numberofpoints > 0)) {
32285  m.insertconstrainedpoints(addin);
32286  }
32287  }
32288 
32289  tv[8] = clock();
32290 
32291  if (!b->quiet) {
32292  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
32293  if ((addin != NULL) && (addin->numberofpoints > 0)) {
32294  printf("Constrained points seconds: %g\n", ((REAL)(tv[8]-tv[7]))/cps);
32295  }
32296  }
32297  }
32298 
32299  if (b->quality) {
32300  m.delaunayrefinement();
32301  }
32302 
32303  tv[9] = clock();
32304 
32305  if (!b->quiet) {
32306  if (b->quality) {
32307  printf("Refinement seconds: %g\n", ((REAL)(tv[9] - tv[8])) / cps);
32308  }
32309  }
32310 
32311  if ((b->plc || b->refine) && (b->optlevel > 0)) {
32312  m.optimizemesh();
32313  }
32314 
32315  tv[10] = clock();
32316 
32317  if (!b->quiet) {
32318  if ((b->plc || b->refine) && (b->optlevel > 0)) {
32319  printf("Optimization seconds: %g\n", ((REAL)(tv[10] - tv[9])) / cps);
32320  }
32321  }
32322 
32323 
32324  if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
32325  || (b->refine && (in->numberofcorners == 10)))) {
32326  m.jettisonnodes();
32327  }
32328 
32329  if ((b->order == 2) && !b->convex) {
32330  m.highorder();
32331  }
32332 
32333  if (!b->quiet) {
32334  printf("\n");
32335  }
32336 
32337  if (out != (tetgenio *) NULL) {
32338  out->firstnumber = in->firstnumber;
32339  out->mesh_dim = in->mesh_dim;
32340  }
32341 
32342  if (b->nonodewritten || b->noiterationnum) {
32343  if (!b->quiet) {
32344  printf("NOT writing a .node file.\n");
32345  }
32346  } else {
32347  m.outnodes(out);
32348  }
32349 
32350  if (b->noelewritten) {
32351  if (!b->quiet) {
32352  printf("NOT writing an .ele file.\n");
32353  }
32354  m.indexelements();
32355  } else {
32356  if (m.tetrahedrons->items > 0l) {
32357  m.outelements(out);
32358  }
32359  }
32360 
32361  if (b->nofacewritten) {
32362  if (!b->quiet) {
32363  printf("NOT writing an .face file.\n");
32364  }
32365  } else {
32366  if (b->facesout) {
32367  if (m.tetrahedrons->items > 0l) {
32368  m.outfaces(out); // Output all faces.
32369  }
32370  } else {
32371  if (b->plc || b->refine) {
32372  if (m.subfaces->items > 0l) {
32373  m.outsubfaces(out); // Output boundary faces.
32374  }
32375  } else {
32376  if (m.tetrahedrons->items > 0l) {
32377  m.outhullfaces(out); // Output convex hull faces.
32378  }
32379  }
32380  }
32381  }
32382 
32383 
32384  if (b->nofacewritten) {
32385  if (!b->quiet) {
32386  printf("NOT writing an .edge file.\n");
32387  }
32388  } else {
32389  if (b->edgesout) { // -e
32390  m.outedges(out); // output all mesh edges.
32391  } else {
32392  if (b->plc || b->refine) {
32393  m.outsubsegments(out); // output subsegments.
32394  }
32395  }
32396  }
32397 
32398  if ((b->plc || b->refine) && b->metric) { // -m
32399  m.outmetrics(out);
32400  }
32401 
32402  if (!out && b->plc &&
32403  ((b->object == tetgenbehavior::OFF) ||
32404  (b->object == tetgenbehavior::PLY) ||
32405  (b->object == tetgenbehavior::STL))) {
32406  m.outsmesh(b->outfilename);
32407  }
32408 
32409  if (!out && b->meditview) {
32410  m.outmesh2medit(b->outfilename);
32411  }
32412 
32413 
32414  if (!out && b->vtkview) {
32415  m.outmesh2vtk(b->outfilename);
32416  }
32417 
32418  if (b->neighout) {
32419  m.outneighbors(out);
32420  }
32421 
32422  if (b->voroout) {
32423  m.outvoronoi(out);
32424  }
32425 
32426 
32427  tv[11] = clock();
32428 
32429  if (!b->quiet) {
32430  printf("\nOutput seconds: %g\n", ((REAL)(tv[11] - tv[10])) / cps);
32431  printf("Total running seconds: %g\n", ((REAL)(tv[11] - tv[0])) / cps);
32432  }
32433 
32434  if (b->docheck) {
32435  m.checkmesh(0);
32436  if (b->plc || b->refine) {
32437  m.checkshells();
32438  m.checksegments();
32439  }
32440  if (b->docheck > 1) {
32441  m.checkdelaunay();
32442  }
32443  }
32444 
32445  if (!b->quiet) {
32446  m.statistics();
32447  }
32448 }
32449 
32450 #ifndef TETLIBRARY
32451 
32453 // //
32454 // main() The command line interface of TetGen. //
32455 // //
32457 
32458 int main(int argc, char *argv[])
32459 
32460 #else // with TETLIBRARY
32461 
32463 // //
32464 // tetrahedralize() The library interface of TetGen. //
32465 // //
32467 
32468 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
32469  tetgenio *addin, tetgenio *bgmin)
32470 
32471 #endif // not TETLIBRARY
32472 
32473 {
32474  tetgenbehavior b;
32475 
32476 #ifndef TETLIBRARY
32477 
32478  tetgenio in, addin, bgmin;
32479 
32480  if (!b.parse_commandline(argc, argv)) {
32481  terminatetetgen(NULL, 10);
32482  }
32483 
32484  // Read input files.
32485  if (b.refine) { // -r
32486  if (!in.load_tetmesh(b.infilename, (int) b.object)) {
32487  terminatetetgen(NULL, 10);
32488  }
32489  } else { // -p
32490  if (!in.load_plc(b.infilename, (int) b.object)) {
32491  terminatetetgen(NULL, 10);
32492  }
32493  }
32494  if (b.insertaddpoints) { // -i
32495  // Try to read a .a.node file.
32496  addin.load_node(b.addinfilename);
32497  }
32498  if (b.metric) { // -m
32499  // Try to read a background mesh in files .b.node, .b.ele.
32500  bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
32501  }
32502 
32503  tetrahedralize(&b, &in, NULL, &addin, &bgmin);
32504 
32505  return 0;
32506 
32507 #else // with TETLIBRARY
32508 
32509  if (!b.parse_commandline(switches)) {
32510  terminatetetgen(NULL, 10);
32511  }
32512  tetrahedralize(&b, in, out, addin, bgmin);
32513 
32514 #endif // not TETLIBRARY
32515 }
32516 
32520